]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/master' into samual/notification_rewrite
authorSamual Lenks <samual@xonotic.org>
Thu, 27 Sep 2012 04:43:58 +0000 (00:43 -0400)
committerSamual Lenks <samual@xonotic.org>
Thu, 27 Sep 2012 04:43:58 +0000 (00:43 -0400)
Conflicts:
qcsrc/client/Main.qc
qcsrc/server/g_world.qc

13 files changed:
qcsrc/client/Main.qc
qcsrc/client/progs.src
qcsrc/common/constants.qh
qcsrc/common/notifications.qc [new file with mode: 0644]
qcsrc/server/autocvars.qh
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/progs.src

index c71c787c6e679cd74ecba9c869f3f7b604ff8b21..a1bd34534220afea04970c35efd055e19b87ecf3 100644 (file)
@@ -154,7 +154,8 @@ void CSQC_Init(void)
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
-
+       CALL_ACCUMULATED_FUNCTION(DecNotifs);
+       
        WaypointSprite_Load();
 
        // precaches
@@ -1186,6 +1187,10 @@ float CSQC_Parse_TempEntity()
                        cl_notice_read();
                        bHandled = true;
                        break;
+               case TE_CSQC_NOTIFICATION:
+                       Local_Notification(ReadShort(), ReadCoord(), ReadString(), ReadString(), ReadString());
+                       bHandled = true;
+                       break;
                default:
                        // No special logic for this temporary entity; return 0 so the engine can handle it
                        bHandled = false;
index 0922433eebdecd2d6c3c229636162e1475c6e56b..8fc2b9b73d82df18f37024d4a63edd7207e5ace6 100644 (file)
@@ -50,6 +50,8 @@ vehicles/vehicles.qh
 ../csqcmodellib/cl_player.qh
 projectile.qh
 
+../common/notifications.qc
+
 sortlist.qc
 miscfunctions.qc
 teamplay.qc
index 9717905b6e0f61c5d8a863a0467b9ae4826446eb..5214d519c4a7b3cec750002b72032a595a3f1cf0 100644 (file)
@@ -47,6 +47,7 @@ const float TE_CSQC_MINELAYER_MAXMINES = 117;
 const float TE_CSQC_HAGAR_MAXROCKETS = 118;
 const float TE_CSQC_VEHICLESETUP = 119;
 const float TE_CSQC_SVNOTICE = 120;
+const float TE_CSQC_NOTIFICATION = 121;
 
 const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
 const float RACE_NET_CHECKPOINT_CLEAR = 1;
@@ -364,6 +365,29 @@ float SPECIES_RESERVED     = 15;
 
 // Deathtypes (weapon deathtypes are the IT_* constants below)
 // NOTE: when adding death types, please add an explanation to Docs/spamlog.txt too.
+#define VAR_TO_TEXT2(var) #var
+#define CHECK_FIELD_COUNT(field,first,count) if(!field) { field = (first + count); ++count; }
+#define CHECK_MAX_DEATHTYPES(name,count) if(count == DT_MAX) { error(strcat("Maximum deathtypes hit: ", VAR_TO_TEXT2(name), ": ", ftos(count), ".\n")); }
+
+#define DT_FIRST 10000
+#define DT_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
+float DT_COUNT;
+
+#define DEATHTYPE(name,type,notification) \
+       float name; \
+       void DecDeathtype_##name() \
+       { \
+               CHECK_FIELD_COUNT(name, DT_FIRST, DT_COUNT) \
+               CHECK_MAX_DEATHTYPES(name, DT_COUNT) \
+       }
+       //ACCUMULATE_FUNCTION(DecDeathtypes, DecDeathtype_##name)
+
+#define DEATHTYPES \
+       DEATHTYPE(DEATH_SPECIAL_START, MSG_CENTER, FALSE) \
+       #undef DEATHTYPE
+
+DEATHTYPES
+
 float DEATH_SPECIAL_START = 10000;
 float DEATH_FALL = 10000;
 float DEATH_TELEFRAG = 10001;
diff --git a/qcsrc/common/notifications.qc b/qcsrc/common/notifications.qc
new file mode 100644 (file)
index 0000000..6dffb66
--- /dev/null
@@ -0,0 +1,404 @@
+// ================================================
+//  Unified notification system, written by Samual
+//  Last updated: September, 2012
+// ================================================
+
+// main types/groups of notifications
+#define MSG_INFO 1 // "Global" information messages (sent to console)
+#define MSG_NOTIFY 2 // "Global" events to be sent to the notification panel
+#define MSG_CENTER 3 // "Personal" centerprint messages
+#define MSG_WEAPON 4 // "Personal" weapon messages (like "You got the Nex", sent to weapon notify panel)
+
+// expand multiple arguments into one argument
+#define XPND4(a,b,c,d) a, b, c, d
+#define XPND3(a,b,c) a, b, c
+#define XPND2(a,b) a, b
+
+// allow sending of notifications to also pass through to spectators (specifically for centerprints)
+#ifdef SVQC
+#define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
+#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
+#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
+#endif
+
+#define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
+#define NOTIF_MATCH(a,b) if(min(NOTIF_MAX, a) == b)
+#define VAR_TO_TEXT(var) #var
+
+#define CHECK_FIELD_AND_COUNT(field,count) if(!field) { field = (NOTIF_FIRST + count); ++count; }
+#define CHECK_MAX_NOTIFICATIONS(name,count) if(count == NOTIF_MAX) { error(strcat("Maximum notifications hit: ", VAR_TO_TEXT(name), ": ", ftos(count), ".\n")); }
+
+
+// ====================================
+//  Notifications List and Information
+// ====================================
+/*
+ List of all notifications (including identifiers and display information)
+ Format: name, args, *icon/CPID, *durcnt, normal, gentle
+ Asterisked fields are not present in all notification types.
+ Specifications:
+    Name of notification
+    Arguments for sprintf(string, args), if no args needed then use ""
+    *Icon/CPID:
+      MSG_NOTIFY: STRING: icon string name for the hud notify panel, "" if no icon is used
+      MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
+    *Duration/Countdown:
+      MSG_CENTER: XPND2(FLOAT, FLOAT): extra arguments for centerprint messages
+    Normal message (string for sprintf when gentle messages are NOT enabled)
+    Gentle message (string for sprintf when gentle messages ARE enabled)
+
+ Messages have ^F1, ^F2, and ^BG in them-- these are replaced
+ with colors according to the cvars the user has chosen.
+    ^F1 = highest priority, "primary"
+    ^F2 = next highest priority, "secondary"
+    ^BG = normal/less important priority, "tertiary"
+
+ Guidlines (please try and follow these):
+    ALWAYS start the string with a color, preferably background.
+    ALWAYS end messages with a new line.
+    ALWAYS properly use tab spacing to even out the notifications.
+    NEVER re-declare an event twice.
+    NEVER add or remove fields from the format, it SHOULD already work.
+    ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
+    Be clean and simple with your notification naming, nothing too long.
+    Keep the notifications in alphabetical order.
+*/
+#define MSG_INFO_NOTIFICATIONS \
+       MSG_INFO_NOTIF(DEATH_MARBLES_LOST, XPND3(s1, s2, s3), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
+       #undef MSG_INFO_NOTIF
+
+#define MSG_NOTIFY_NOTIFICATIONS \
+       MSG_NOTIFY_NOTIF(DEATH_MARBLES_LOST2, XPND3(s1, s2, s3), "notify_death", _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
+       #undef MSG_NOTIFY_NOTIF
+
+#define MSG_CENTER_NOTIFICATIONS \
+       MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_SHIELDED,             "",                             CPID_CTF_CAPTURESHIELD, XPND2(0, 0), _("^BGYou are now ^F1shielded^BG from the flag\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
+       MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_FREE,                 "",                             CPID_CTF_CAPTURESHIELD, XPND2(0, 0), _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "") \
+       MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS,                                 XPND2(s1, s2, s3),      CPID_CTF_PASS,                  XPND2(0, 0), _("^BG%s passed the ^F1%s^BG to %s"), "") \
+       MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_SENT,                    XPND2(s1, s2),          CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou passed the ^F1%s^BG to %s"), "") \
+       MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_RECEIVED,                XPND2(s1, s2),          CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou received the ^F1%s^BG from %s"), "") \
+       MSG_CENTER_NOTIF(CENTER_CTF_EVENT_RETURN,                               s1,                                     CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou returned the ^F1%s"), "") \
+       MSG_CENTER_NOTIF(CENTER_CTF_EVENT_CAPTURE,                              s1,                                     NO_CPID,                                XPND2(0, 0), _("^BGYou captured the ^F1%s"), "") \
+       #undef MSG_CENTER_NOTIF
+
+#define MSG_WEAPON_NOTIFICATIONS \
+       MSG_WEAPON_NOTIF(DEATH_MARBLES_LOST3, XPND3(s1, s2, s3), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
+       #undef MSG_WEAPON_NOTIF
+
+
+// ====================================
+//  Initialization/Create Declarations
+// ====================================
+
+#define NOTIF_FIRST 1
+#define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
+float NOTIF_INFO_COUNT;
+float NOTIF_NOTIFY_COUNT;
+float NOTIF_CENTER_COUNT;
+float NOTIF_WEAPON_COUNT;
+float NOTIF_CPID_COUNT;
+       
+#define MSG_INFO_NOTIF(name,args,normal,gentle) \
+       float name; \
+       void DecNotif_##name() \
+       { \
+               CHECK_FIELD_AND_COUNT(name, NOTIF_INFO_COUNT) \
+               CHECK_MAX_NOTIFICATIONS(name, NOTIF_INFO_COUNT) \
+       } \
+       ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
+
+#define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
+       float name; \
+       void DecNotif_##name() \
+       { \
+               CHECK_FIELD_AND_COUNT(name, NOTIF_NOTIFY_COUNT) \
+               CHECK_MAX_NOTIFICATIONS(name, NOTIF_NOTIFY_COUNT) \
+       } \
+       ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
+
+#define MSG_CENTER_NOTIF(name,args,cpid,durcnt,normal,gentle) \
+       float name; \
+       float cpid; \
+       void DecNotif_##name() \
+       { \
+               CHECK_FIELD_AND_COUNT(name, NOTIF_CENTER_COUNT) \
+               CHECK_FIELD_AND_COUNT(cpid, NOTIF_CPID_COUNT) \
+               CHECK_MAX_NOTIFICATIONS(name, NOTIF_CENTER_COUNT) \
+       } \
+       ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
+
+#define MSG_WEAPON_NOTIF(name,args,normal,gentle) \
+       float name; \
+       void DecNotif_##name() \
+       { \
+               CHECK_FIELD_AND_COUNT(name, NOTIF_WEAPON_COUNT) \
+               CHECK_MAX_NOTIFICATIONS(name, NOTIF_WEAPON_COUNT) \
+       } \
+       ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
+
+// NOW we actually activate the declarations
+MSG_INFO_NOTIFICATIONS
+MSG_NOTIFY_NOTIFICATIONS
+MSG_CENTER_NOTIFICATIONS
+MSG_WEAPON_NOTIFICATIONS
+
+
+// ======================
+//  Supporting Functions
+// ======================
+
+// select between the normal or the gentle message string based on client (or server) settings
+string normal_or_gentle(string normal, string gentle)
+{
+       #ifdef CSQC
+       if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
+       #else
+       if(autocvar_sv_gentle)
+       #endif
+               return ((gentle != "") ? gentle : normal);
+       else
+               return normal;
+}
+
+// get the actual name of a notification and return it as a string
+string Get_Notif_Name(float net_type, float net_name)
+{
+       switch(net_type)
+       {
+               case MSG_INFO:
+               {
+                       #define MSG_INFO_NOTIF(name,args,normal,gentle) \
+                               { NOTIF_MATCH(name,net_name) { return VAR_TO_TEXT(name); } }
+                       MSG_INFO_NOTIFICATIONS
+                       break;
+               }
+               case MSG_NOTIFY:
+               {
+                       #define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
+                               { NOTIF_MATCH(name,net_name) { return VAR_TO_TEXT(name); } }
+                       MSG_NOTIFY_NOTIFICATIONS
+                       break;
+               }
+               case MSG_CENTER:
+               {
+                       #define MSG_CENTER_NOTIF(name,args,cpid,durcnt,normal,gentle) \
+                               { NOTIF_MATCH(name,net_name) { return VAR_TO_TEXT(name); } }
+                       MSG_CENTER_NOTIFICATIONS
+                       break;
+               }
+               case MSG_WEAPON:
+               {
+                       #define MSG_WEAPON_NOTIF(name,args,normal,gentle) \
+                               { NOTIF_MATCH(name,net_name) { return VAR_TO_TEXT(name); } }
+                       MSG_WEAPON_NOTIFICATIONS
+                       break;
+               }
+       }
+       return "";
+}
+
+// color code replace, place inside of sprintf and parse the string
+string CCR(string input)
+{
+       input = strreplace("^F1", "^3", input);
+       input = strreplace("^F2", "^2", input);
+       input = strreplace("^K1", "^1", input);
+       input = strreplace("^K2", "^5", input);
+       input = strreplace("^BG", "^7", input);
+
+       input = strreplace("^N", "^7", input); // "none"-- reset to white
+
+       return input;
+}
+
+
+// ===============================
+//  Frontend Notification Pushing
+// ===============================
+
+#ifdef CSQC
+void Local_Notification(float net_type, float net_name, string s1, string s2, string s3)
+{
+       switch(net_type)
+       {
+               case MSG_INFO:
+               {
+                       #define MSG_INFO_NOTIF(name,args,normal,gentle) \
+                               { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
+
+                       MSG_INFO_NOTIFICATIONS
+                       break;
+               }
+               case MSG_NOTIFY:
+               {
+                       #define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
+                               { NOTIF_MATCH(name,net_name) { print("unhandled\n"); } }
+                               
+                       MSG_NOTIFY_NOTIFICATIONS
+                       break;
+               }
+               case MSG_CENTER:
+               {
+                       #define MSG_CENTER_NOTIF(name,args,cpid,durcnt,normal,gentle) \
+                               { NOTIF_MATCH(name, net_name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); } }
+
+                       MSG_CENTER_NOTIFICATIONS
+                       break;
+               }
+               case MSG_WEAPON:
+               {
+                       #define MSG_WEAPON_NOTIF(name,args,normal,gentle) \
+                               { NOTIF_MATCH(name,net_name) { print("unhandled\n"); } }
+                               
+                       MSG_WEAPON_NOTIFICATIONS
+                       break;
+               }
+       }
+}
+#endif
+
+
+// =========================
+//  Notification Networking
+// =========================
+
+#ifdef SVQC
+void Send_Notification(float net_type, entity client, float net_name, string s1, string s2, string s3)
+{
+       if(net_type && net_name)
+       {
+               print("notification: ", Get_Notif_Name(net_type, net_name), ": ", ftos(net_name), ".\n");
+               
+               if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
+               {
+                       // personal/direct notification sent to ONE person and their spectators
+                       msg_entity = client;
+                       WRITESPECTATABLE_MSG_ONE({
+                               WriteByte(MSG_ONE, SVC_TEMPENTITY);
+                               WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
+                               WriteShort(MSG_ONE, net_type);
+                               WriteCoord(MSG_ONE, net_name);
+                               WriteString(MSG_ONE, s1);
+                               WriteString(MSG_ONE, s2);
+                               WriteString(MSG_ALL, s3);
+                       });
+               }
+               else
+               {
+                       // global notification sent to EVERYONE
+                       WriteByte(MSG_ALL, SVC_TEMPENTITY);
+                       WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
+                       WriteShort(MSG_ALL, net_type);
+                       WriteCoord(MSG_ALL, net_name);
+                       WriteString(MSG_ALL, s1);
+                       WriteString(MSG_ALL, s2);
+                       WriteString(MSG_ALL, s3);
+               }
+
+               if(!server_is_local && ((net_type == MSG_INFO || net_type == MSG_NOTIFY) || client == world))
+               {
+                       switch(net_type)
+                       {
+                               case MSG_INFO:
+                               {
+                                       #define MSG_INFO_NOTIF(name,args,normal,gentle) \
+                                               { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
+
+                                       MSG_INFO_NOTIFICATIONS
+                                       break;
+                               }
+
+                               case MSG_NOTIFY:
+                               {
+                                       #define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
+                                               { NOTIF_MATCH(name,net_name) { print("unhandled\n"); } }
+                               
+                                       MSG_NOTIFY_NOTIFICATIONS
+                                       break;
+                               }
+                       }
+               }
+       }
+       else { backtrace("Incorrect usage of Send_Notification!\n"); }
+}
+
+void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, string s3)
+{
+       entity tmp_entity;
+       FOR_EACH_REALCLIENT(tmp_entity)
+       {
+               if(tmp_entity.classname == STR_PLAYER)
+               if(tmp_entity.team == targetteam)
+               if(tmp_entity != except)
+               {
+                       Send_Notification(net_type, tmp_entity, net_name, s1, s2, s3);
+               }
+       }
+}
+
+// use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(..., world, ...)
+void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, string s3)
+{
+       entity tmp_entity;
+       FOR_EACH_REALCLIENT(tmp_entity)
+       {
+               if((tmp_entity.classname == STR_PLAYER) || spectators)
+               if(tmp_entity != except)
+               {
+                       Send_Notification(net_type, tmp_entity, net_name, s1, s2, s3);
+               }
+       }
+}
+
+// LEGACY NOTIFICATION SYSTEMS
+void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
+{
+       WriteByte(MSG_ALL, SVC_TEMPENTITY);
+       WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
+       WriteString(MSG_ALL, s1);
+       WriteString(MSG_ALL, s2);
+       WriteString(MSG_ALL, s3);
+       WriteShort(MSG_ALL, msg);
+       WriteByte(MSG_ALL, type);
+}
+
+// Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
+void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
+{
+       if (clienttype(e) == CLIENTTYPE_REAL)
+       {
+               msg_entity = e;
+               WRITESPECTATABLE_MSG_ONE({
+                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
+                       WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
+                       WriteString(MSG_ONE, s1);
+                       WriteString(MSG_ONE, s2);
+                       WriteShort(MSG_ONE, msg);
+                       WriteByte(MSG_ONE, type);
+               });
+       }
+}
+
+void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
+{
+       if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
+       {
+               msg_entity = e;
+               WRITESPECTATABLE_MSG_ONE({
+                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
+                       WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
+                       WriteByte(MSG_ONE, id);
+                       WriteString(MSG_ONE, s);
+                       if (id != 0 && s != "")
+                       {
+                               WriteByte(MSG_ONE, duration);
+                               WriteByte(MSG_ONE, countdown_num);
+                       }
+               });
+       }
+}
+void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
+{
+       Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
+}
+#endif
index 16a7193c13710903da8cd9ed2db5143802504508..237dc56513f95ee41117b58b86273daef35b42f8 100644 (file)
@@ -1175,6 +1175,7 @@ float autocvar_sv_fraginfo_stats;
 float autocvar_sv_friction;
 float autocvar_sv_friction_on_land;
 float autocvar_sv_gameplayfix_q2airaccelerate;
+float autocvar_sv_gentle;
 #define autocvar_sv_gravity cvar("sv_gravity")
 string autocvar_sv_intermission_cdtrack;
 string autocvar_sv_jumpspeedcap_max;
index 9d6bcf798d8b3026e6fb542731491923ba99b715..c9da49477595999a7d50cf7495401e15427d28d4 100644 (file)
@@ -1286,7 +1286,7 @@ void FixClientCvars(entity e)
                stuffcmd(e, "cl_cmd settemp cl_movecliptokeyboard 2\n");
        if(autocvar_g_antilag == 3) // client side hitscan
                stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
-       if(sv_gentle)
+       if(autocvar_sv_gentle)
                stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
        /*
         * we no longer need to stuff this. Remove this comment block if you feel
@@ -1363,6 +1363,16 @@ void ClientConnect (void)
        self.flags = FL_CLIENT;
        self.version_nagtime = time + 10 + random() * 10;
 
+       if(self.netaddress == "local")
+       {
+               print("^3server is local!\n");
+
+               if(server_is_local)
+                       error("Multiple local clients???");
+               else
+                       server_is_local = TRUE;
+       }
+
        if(player_count<0)
        {
                dprint("BUG player count is lower than zero, this cannot happen!\n");
index 3e560bd2452a71020d339d7ed22830a76b212ec8..4b5bca748c54dd5e39597525325f961b9838eef3 100644 (file)
@@ -536,7 +536,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
                        {
                                self.pain_finished = time + 0.5;        //Supajoe
 
-                               if(sv_gentle < 1) {
+                               if(autocvar_sv_gentle < 1) {
                                        if(self.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
                                        {
                                                if (!self.animstate_override)
@@ -644,7 +644,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
                if(valid_damage_for_weaponstats)
                        WeaponStats_LogKill(awep, abot, self.weapon, vbot);
 
-               if(sv_gentle < 1) // TODO make a "gentle" version?
+               if(autocvar_sv_gentle < 1) // TODO make a "gentle" version?
                if(sound_allowed(MSG_BROADCAST, attacker))
                {
                        if(deathtype == DEATH_DROWN)
@@ -786,7 +786,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
                // set up to fade out later
                SUB_SetFade (self, time + 6 + random (), 1);
 
-               if(sv_gentle > 0 || autocvar_ekg) {
+               if(autocvar_sv_gentle > 0 || autocvar_ekg) {
                        // remove corpse
                        PlayerCorpseDamage (inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
                }
@@ -1237,7 +1237,7 @@ void FakeGlobalSound(string sample, float chan, float voicetype)
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        msg_entity = self;
@@ -1255,7 +1255,7 @@ void FakeGlobalSound(string sample, float chan, float voicetype)
                                        setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        msg_entity = self;
                        if (msg_entity.cvar_cl_voice_directional >= 1)
@@ -1334,7 +1334,7 @@ void GlobalSound(string sample, float chan, float voicetype)
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        FOR_EACH_REALCLIENT(msg_entity)
@@ -1352,7 +1352,7 @@ void GlobalSound(string sample, float chan, float voicetype)
                                        setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        FOR_EACH_REALCLIENT(msg_entity)
                        {
index 9068fa75bf53e95400df5e635e8551faa3ae3a2c..6b3b734ed8580b3ab63d216399a997da850f076a 100644 (file)
@@ -39,7 +39,6 @@ float g_pickup_respawntimejitter_powerup;
 float g_jetpack;
 
 float sv_clones;
-float sv_gentle;
 float sv_foginterval;
 
 entity activator;
@@ -58,6 +57,8 @@ float team1_score, team2_score, team3_score, team4_score;
 
 float maxclients;
 
+float server_is_local; // innocent until proven guilty by ClientConnect() in cl_client.qc
+
 // Fields
 
 .void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage;
index d2cc61db3346cb3405ca086e9d025657fd2a4c6f..f23988c7e8c2c15e97135690e1867cb5af6414e2 100644 (file)
@@ -308,32 +308,13 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed)
        GameLogEcho(s);
 }
 
-void Send_KillNotification (string s1, string s2, string s3, float msg, float type)
+void Obituary_Notification(entity notif_target, string s1, string s2, string s3, float deathtype)
 {
-       WriteByte(MSG_ALL, SVC_TEMPENTITY);
-       WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
-       WriteString(MSG_ALL, s1);
-       WriteString(MSG_ALL, s2);
-       WriteString(MSG_ALL, s3);
-       WriteShort(MSG_ALL, msg);
-       WriteByte(MSG_ALL, type);
-}
+       #define DEATHTYPE(name,type,notification) \
+               { if(deathtype == max(0, name)) { Send_Notification(type, notif_target, notification, s1, s2, s3); return; } }
 
-// Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
-void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
-{
-       if (clienttype(e) == CLIENTTYPE_REAL)
-       {
-               msg_entity = e;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
-                       WriteString(MSG_ONE, s1);
-                       WriteString(MSG_ONE, s2);
-                       WriteShort(MSG_ONE, msg);
-                       WriteByte(MSG_ONE, type);
-               });
-       }
+       DEATHTYPES
+       backtrace("Unhandled deathtype. Please notify Samual!\n");
 }
 
 void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
@@ -341,6 +322,8 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
        string  s, a, msg;
        float w, type;
 
+       string s1, s2, s3;
+
        if (targ.classname == "player")
        {
                s = targ.netname;
@@ -348,12 +331,10 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
 
                if (targ == attacker) // suicides
                {
-                       if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
-                               msg = ColoredTeamName(targ.team); // TODO: check if needed?
-                       else
-                               msg = "";
-            if(!g_cts) // no "killed your own dumb self" message in CTS
-                Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE);
+                       s1 = ((deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) ? ColoredTeamName(targ.team) : "");
+
+                       // no "killed your own dumb self" message in CTS
+            if(!g_cts) { Obituary_Notification(targ, s1, "", "", deathtype); }
 
                        if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET)
                        {
@@ -361,32 +342,24 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
                                GiveFrags(attacker, targ, -1, deathtype);
                        }
 
-                       if (targ.killcount > 2)
-                               msg = ftos(targ.killcount);
-                       else
-                               msg = "";
-                       if(teamplay && deathtype == DEATH_MIRRORDAMAGE)
-                       {
-                               if(attacker.team == COLOR_TEAM1)
-                                       deathtype = KILL_TEAM_RED;
-                               else
-                                       deathtype = KILL_TEAM_BLUE;
-                       }
+                       s1 = targ.netname;
+                       s2 = ((targ.killcount > 2) ? ftos(targ.killcount) : "");
+                               
+                       //if(teamplay && deathtype == DEATH_MIRRORDAMAGE)
+                       //      { deathtype = ((attacker.team == COLOR_TEAM1) ? KILL_TEAM_SUICIDE_RED : KILL_TEAM_SUICIDE_BLUE); }
 
-                       Send_KillNotification(s, msg, ftos(w), deathtype, MSG_SUICIDE);
+                       Obituary_Notification(world, s1, s2, "", deathtype);
+                       //Send_KillNotification(s, s2, ftos(w), deathtype, MSG_SUICIDE);
                }
                else if (attacker.classname == "player")
                {
                        if(!IsDifferentTeam(attacker, targ))
                        {
-                               if(attacker.team == COLOR_TEAM1)
-                                       type = KILL_TEAM_RED;
-                               else
-                                       type = KILL_TEAM_BLUE;
+                               //type = ((attacker.team == COLOR_TEAM1) ? KILL_TEAM_FRAG_RED : KILL_TEAM_FRAG_BLUE);
 
                                GiveFrags(attacker, targ, -1, deathtype);
 
-                               Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL);
+                               //Send_CSQC_KillCenterprint(attacker, s, "", type);
 
                                if (targ.killcount > 2)
                                        msg = ftos(targ.killcount);
index 4cd5cc810a1c9f456bc372c0e8106e9b2d274488..0284280b4a225f44b654da8b983f001e3a140096 100644 (file)
@@ -554,6 +554,8 @@ void spawnfunc___init_dedicated_server(void)
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
 
+       DecNotifs();
+
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
 }
@@ -599,6 +601,7 @@ void spawnfunc_worldspawn (void)
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
+       CALL_ACCUMULATED_FUNCTION(DecNotifs);
 
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
 
index 20828800deebfdd3d7d0407269179ec0037489a8..08b06f513804b35f018c41a4e6dcad638091d241 100644 (file)
@@ -1171,7 +1171,6 @@ void readlevelcvars(void)
 #endif
 
        sv_clones = cvar("sv_clones");
-       sv_gentle = cvar("sv_gentle");
        sv_foginterval = cvar("sv_foginterval");
        g_cloaked = cvar("g_cloaked");
     if(g_cts)
@@ -1657,34 +1656,6 @@ void precache()
 #endif
 }
 
-// sorry, but using \ in macros breaks line numbers
-#define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
-#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
-#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
-
-
-void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
-{
-       if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
-       {
-               msg_entity = e;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
-                       WriteByte(MSG_ONE, id);
-                       WriteString(MSG_ONE, s);
-                       if (id != 0 && s != "")
-                       {
-                               WriteByte(MSG_ONE, duration);
-                               WriteByte(MSG_ONE, countdown_num);
-                       }
-               });
-       }
-}
-void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
-{
-       Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
-}
 // WARNING: this kills the trace globals
 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
 #define EXACTTRIGGER_INIT  WarpZoneLib_ExactTrigger_Init()
index f453cc22ad727ea81b78f276ff3958aed207bde2..ef426785442866661ad54423515ac73b66df9b1a 100644 (file)
@@ -287,11 +287,11 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        FOR_EACH_REALPLAYER(tmp_player)
        {
                if(tmp_player == sender)
-                       centerprint(tmp_player, strcat("You passed the ", flag.netname, " to ", player.netname));
+                       Send_Notification(MSG_CENTER, tmp_player, CENTER_CTF_EVENT_PASS_SENT, flag.netname, player.netname, "");
                else if(tmp_player == player)
-                       centerprint(tmp_player, strcat("You received the ", flag.netname, " from ", sender.netname));
+                       Send_Notification(MSG_CENTER, tmp_player, CENTER_CTF_EVENT_PASS_RECEIVED, flag.netname, sender.netname, "");
                else if(!IsDifferentTeam(tmp_player, sender))
-                       centerprint(tmp_player, strcat(sender.netname, " passed the ", flag.netname, " to ", player.netname));
+                       Send_Notification(MSG_CENTER, tmp_player, CENTER_CTF_EVENT_PASS, sender.netname, flag.netname, player.netname);
        }
        
        // create new waypoint
index 028519372f025ae24aa923d472ba0a6593de86b7..9c62fedc9a0ba76858e4f570860a058258d55a88 100644 (file)
@@ -86,6 +86,8 @@ scores_rules.qc
 
 miscfunctions.qc
 
+../common/notifications.qc
+
 waypointsprites.qc
 
 bot/bot.qc