X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fnotifications.qc;h=d0bf7bb053a6fbc29a869a2b0cfec2c19ed1a074;hb=497b37952d519057cb29353977b784ca99b3c790;hp=b43914db32417857e931701e0322b5c86b8f8c4b;hpb=774331f6bffb54312749c9d4ee1f8109c9507106;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/notifications.qc b/qcsrc/common/notifications.qc index b43914db3..d0bf7bb05 100644 --- a/qcsrc/common/notifications.qc +++ b/qcsrc/common/notifications.qc @@ -1,88 +1,20 @@ // ================================================ // Unified notification system, written by Samual -// Last updated: December, 2012 +// Last updated: February, 2013 // ================================================ -#ifndef MENUQC -// get the actual name of a notification and return it as a string -string Get_Field_Value(float field, float net_type, float net_name) +entity Get_Notif_Ent(float net_type, float net_name) { - string output = ""; - - #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \ - switch(field) { \ - case F_NAME: { output = VAR_TO_TEXT(name); break; } \ - case F_STRNUM: { output = ftos(strnum); break; } \ - case F_FLNUM: { output = ftos(flnum); break; } } - switch(net_type) { - case MSG_INFO: - { - #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \ - case name: { { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } break; } - - switch(net_name) - { - MSG_INFO_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_INFO, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_INFO_NOTIF - break; - } - case MSG_CENTER: - { - #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \ - case name: { { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } break; } - - switch(net_name) - { - MSG_CENTER_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_CENTER, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_CENTER_NOTIF - break; - } - case MSG_WEAPON: - { - #define MSG_WEAPON_NOTIF(name,infoname,centername) \ - case name: { { GET_FIELD_VALUE_OUTPUT(field,name, \ - max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \ - max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } break; } - - switch(net_name) - { - MSG_WEAPON_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_WEAPON, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_WEAPON_NOTIF - break; - } - case MSG_DEATH: - { - #define MSG_DEATH_NOTIF(name,infoname,centername) \ - case name: { { GET_FIELD_VALUE_OUTPUT(field,name, \ - max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \ - max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } break; } - - switch(net_name) - { - MSG_DEATH_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_DEATH, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_DEATH_NOTIF - break; - } + case MSG_INFO: return msg_info_notifs[net_name - 1]; + case MSG_CENTER: return msg_center_notifs[net_name - 1]; + case MSG_WEAPON: return msg_weapon_notifs[net_name - 1]; + case MSG_DEATH: return msg_death_notifs[net_name - 1]; } - - #undef GET_FIELD_VALUE_OUTPUT - return output; + backtrace(sprintf("Get_Notif_Ent(%d, %d): Improper net type!\n", net_type, net_name)); + return world; } -#endif // ifndef MENUQC // =============================== @@ -91,195 +23,331 @@ string Get_Field_Value(float field, float net_type, float net_name) void Dump_Notifications(float fh, float alsoprint) { - float MSG_INFO_NOTIFS = 0, MSG_CENTER_NOTIFS = 0, MSG_WEAPON_NOTIFS = 0, MSG_DEATH_NOTIFS = 0; + #define NOTIF_WRITE(a) { \ + fputs(fh, a); \ + if(alsoprint) { print(a); } } + #define NOTIF_WRITE_SETA(name,default,text) { \ + notif_msg = \ + sprintf( \ + "seta notification_%s %d \"notif string: %s^7\"\n", \ + name, default, strreplace("\{3}", "", strreplace("\n", "\\n", text)) \ + ); \ + NOTIF_WRITE(notif_msg) } + string notif_msg; + float i; + entity e; + + // Note: This warning only applies to the notifications.cfg file that is output... + + // You ARE supposed to manually edit this function to add i.e. hard coded + // notification variables for mutators or game modes or such and then + // regenerate the notifications.cfg file from the new code. + + NOTIF_WRITE("// ********************************************** //\n"); + NOTIF_WRITE("// ** WARNING - DO NOT MANUALLY EDIT THIS FILE ** //\n"); + NOTIF_WRITE("// ** ** //\n"); + NOTIF_WRITE("// ** This file is automatically generated ** //\n"); + NOTIF_WRITE("// ** by code with the command 'dumpnotifs'. ** //\n"); + NOTIF_WRITE("// ** ** //\n"); + NOTIF_WRITE("// ** If you add a new notification, please ** //\n"); + NOTIF_WRITE("// ** regenerate this file with that command ** //\n"); + NOTIF_WRITE("// ** making sure that the output matches ** //\n"); + NOTIF_WRITE("// ** with the lists and defaults in code. ** //\n"); + NOTIF_WRITE("// ** ** //\n"); + NOTIF_WRITE("// ********************************************** //\n"); + + NOTIF_WRITE("\n// Version number to identify mismatches between code and config file...\n"); + NOTIF_WRITE("// Increment NOTIF_VERSION in common/notifications.qh with any\n"); + NOTIF_WRITE("// new notifications or other changes to notif cvars/this config.\n"); + + NOTIF_WRITE(sprintf("set notification_version %d\n", NOTIF_VERSION)); - #define NOTIF_WRITE(type,name,text) notif_msg = sprintf("seta %s 1 // %s - %s\n", name, type, strreplace("\n", "\\n", text)); fputs(fh, notif_msg); if(alsoprint) { print(strreplace("^", "^^", notif_msg)); } - #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) { ++MSG_INFO_NOTIFS; NOTIF_WRITE("MSG_INFO", VAR_TO_TEXT(name), normal) } - #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) { ++MSG_CENTER_NOTIFS; NOTIF_WRITE("MSG_CENTER", VAR_TO_TEXT(name), normal) } - #define MSG_WEAPON_NOTIF(name,infoname,centername) { ++MSG_WEAPON_NOTIFS; NOTIF_WRITE("MSG_WEAPON", VAR_TO_TEXT(name),sprintf("infoname: %s, centername: %s", VAR_TO_TEXT(infoname), VAR_TO_TEXT(centername))) } - #define MSG_DEATH_NOTIF(name,infoname,centername) { ++MSG_DEATH_NOTIFS; NOTIF_WRITE("MSG_DEATH", VAR_TO_TEXT(name), sprintf("infoname: %s, centername: %s", VAR_TO_TEXT(infoname), VAR_TO_TEXT(centername))) } - MSG_INFO_NOTIFICATIONS - MSG_CENTER_NOTIFICATIONS - MSG_WEAPON_NOTIFICATIONS - MSG_DEATH_NOTIFICATIONS - #undef NOTIF_WRITE - #undef MSG_INFO_NOTIF - #undef MSG_CENTER_NOTIF - #undef MSG_WEAPON_NOTIF - #undef MSG_DEATH_NOTIF + // These notifications will also append their string as a comment... + // This is not necessary, and does not matter if they vary between config versions, + // it is just a semi-helpful tool for those who want to manually change their user settings. + + NOTIF_WRITE(sprintf("\n// MSG_INFO notifications (count = %d):\n", NOTIF_INFO_COUNT)); + for(i = 1; i <= NOTIF_INFO_COUNT; ++i) + { + e = Get_Notif_Ent(MSG_INFO, i); + if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; } + NOTIF_WRITE_SETA(e.nent_name, e.nent_default, e.nent_string); + } + + NOTIF_WRITE(sprintf("\n// MSG_CENTER notifications (count = %d):\n", NOTIF_CENTER_COUNT)); + for(i = 1; i <= NOTIF_CENTER_COUNT; ++i) + { + e = Get_Notif_Ent(MSG_CENTER, i); + if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; } + NOTIF_WRITE_SETA(e.nent_name, e.nent_default, e.nent_string); + } + + NOTIF_WRITE(sprintf("\n// MSG_WEAPON notifications (count = %d):\n", NOTIF_WEAPON_COUNT)); + for(i = 1; i <= NOTIF_WEAPON_COUNT; ++i) + { + e = Get_Notif_Ent(MSG_WEAPON, i); + if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; } + NOTIF_WRITE_SETA(e.nent_name, e.nent_default, sprintf("infoname: %s, centername: %s", + e.nent_msginfo.nent_name, e.nent_msgcenter.nent_name)); + } + + NOTIF_WRITE(sprintf("\n// MSG_DEATH notifications (count = %d):\n", NOTIF_DEATH_COUNT)); + for(i = 1; i <= NOTIF_DEATH_COUNT; ++i) + { + e = Get_Notif_Ent(MSG_DEATH, i); + if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; } + NOTIF_WRITE_SETA(e.nent_name, e.nent_default, sprintf("infoname: %s, centername: %s", + e.nent_msginfo.nent_name, e.nent_msgcenter.nent_name)); + } + + // edit these to match whichever cvars are used for specific notification options + NOTIF_WRITE("\n// HARD CODED notification variables:\n"); + NOTIF_WRITE("seta notification_allow_chatboxprint 1 \"Allow notifications to be printed to chat box by setting notification cvar to 2 (You can also set this cvar to 2 to force ALL notifications to be printed to the chatbox)\"\n"); + NOTIF_WRITE("seta notification_show_sprees 1 \"Print information about sprees in death/kill messages\"\n"); + NOTIF_WRITE("seta notification_version_mismatch_client_error 0 \"Cause a notif error on client if the version in notifications.cfg mismatches the code\"\n"); + NOTIF_WRITE("seta notification_version_mismatch_server_error 1 \"Cause a notif error on server if the version in notifications.cfg mismatches the code\"\n"); + NOTIF_WRITE("seta notification_errors_are_fatal 1 \"If a notification fails upon initialization, cause a Host_Error to stop the program\"\n"); + NOTIF_WRITE("seta notification_ctf_pickup_team_verbose 1 \"Show extra information if a team mate picks up a flag\"\n"); + NOTIF_WRITE("seta notification_ctf_pickup_enemy_verbose 1 \"Show extra information if an enemy picks up a flag\"\n"); + NOTIF_WRITE("seta notification_ctf_capture_verbose 1 \"Show extra information when someone captures a flag\"\n"); + NOTIF_WRITE("seta notification_frag_verbose 1 \"Show extra information when you frag someone (or when you are fragged\"\n"); + + NOTIF_WRITE(sprintf("\n// Notification counts (total = %d): MSG_INFO = %d, MSG_CENTER = %d, MSG_WEAPON = %d, MSG_DEATH = %d\n", + (NOTIF_INFO_COUNT + NOTIF_CENTER_COUNT + NOTIF_WEAPON_COUNT + NOTIF_DEATH_COUNT), + NOTIF_INFO_COUNT, NOTIF_CENTER_COUNT, NOTIF_WEAPON_COUNT, NOTIF_DEATH_COUNT)); - print(sprintf("Notification counts: MSG_INFO = %d, MSG_CENTER = %d, MSG_WEAPON = %d, MSG_DEATH = %d\n", MSG_INFO_NOTIFS, MSG_CENTER_NOTIFS, MSG_WEAPON_NOTIFS, MSG_DEATH_NOTIFS)); return; + #undef NOTIF_WRITE_SETA + #undef NOTIF_WRITE } -#ifndef MENUQC -#ifdef CSQC -void HUD_Notify_Push(string icon, string attacker, string victim) +#ifdef SVQC +void Notification_GetCvars() { - if(icon != "") - { - --kn_index; - if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; } - killnotify_times[kn_index] = time; + GetCvars_handleFloat(get_cvars_s, get_cvars_f, FRAG_VERBOSE, "notification_frag_verbose"); +} +#endif + +string Local_Notification_sprintf(string input, string args, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4) +{ + #ifdef NOTIFICATIONS_DEBUG + dprint( + sprintf("Local_Notification_sprintf('%s^7', '%s', %s, %s);\n", + strreplace("\n", "\\n", input), + args, + sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4), + sprintf("%d, %d, %d, %d", f1, f2, f3, f4) + ) + ); + #endif + + string selected; + float sel_num; + for(sel_num = 0; sel_num < NOTIF_MAX_ARGS; ++sel_num) { arg_slot[sel_num] = ""; } + + #ifdef CSQC + string tmp_s; + #endif - // icon - if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); } - killnotify_icon[kn_index] = strzone(icon); + for(sel_num = 0;(args != "");) + { + selected = car(args); args = cdr(args); + NOTIF_HIT_MAX(NOTIF_MAX_ARGS, "Local_Notification_sprintf") + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #ifdef CSQC \ + #if (prog == ARG_DOUBLE) || (prog == ARG_TRIPLE) || (prog == ARG_CSQC) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif \ + #else \ + #if (prog == ARG_DOUBLE) || (prog == ARG_TRIPLE) || (prog == ARG_SVQC) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + NOTIF_HIT_UNKNOWN(NOTIF_MAX_ARGS, "Local_Notification_sprintf") + } + } + return sprintf(input, arg_slot[0], arg_slot[1], arg_slot[2], arg_slot[3], arg_slot[4], arg_slot[5], arg_slot[6]); +} - // attacker - if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); } - killnotify_attackers[kn_index] = strzone(attacker); +#ifdef CSQC +void Local_Notification_HUD_Notify_Push(string icon, string hudargs, string s1, string s2, string s3, string s4) +{ + string selected; + float sel_num; + arg_slot[0] = ""; arg_slot[1] = ""; - // victim - if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); } - killnotify_victims[kn_index] = strzone(victim); + for(sel_num = 0;(hudargs != "");) + { + selected = car(hudargs); hudargs = cdr(hudargs); + NOTIF_HIT_MAX(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push") + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #if (prog == ARG_TRIPLE) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + NOTIF_HIT_UNKNOWN(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push") + } } + HUD_Notify_Push(icon, arg_slot[0], arg_slot[1]); } -#endif // ifdef CSQC +#endif void Local_Notification(float net_type, float net_name, ...count) { - if(net_type && net_name) + // check supplied type and name for errors + string checkargs = ""; + #define CHECKARG_TYPENAME(type) case MSG_##type##: \ + { if(!net_name || (net_name > NOTIF_##type##_COUNT)) \ + { checkargs = sprintf("Improper name: %d!", net_name); } break; } + switch(net_type) { - float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name)); - float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name)); - - string s1 = ((0 < stringcount) ? ...(0, string) : NO_STR_ARG); - string s2 = ((1 < stringcount) ? ...(1, string) : NO_STR_ARG); - string s3 = ((2 < stringcount) ? ...(2, string) : NO_STR_ARG); - string s4 = ((3 < stringcount) ? ...(3, string) : NO_STR_ARG); - float f1 = ((stringcount < count) ? ...(stringcount, float) : NO_FL_ARG); - float f2 = (((stringcount + 1) < count) ? ...((stringcount + 1), float) : NO_FL_ARG); - float f3 = (((stringcount + 2) < count) ? ...((stringcount + 2), float) : NO_FL_ARG); - float f4 = (((stringcount + 3) < count) ? ...((stringcount + 3), float) : NO_FL_ARG); - - string tmp_s; - - dprint("Local_Notification(", ftos(net_type), ", ", Get_Field_Value(F_NAME, net_type, net_name), strcat(", ", s1, ", ", s2, ", ", s3, ", ", s4, ", "), strcat(ftos(f1), strcat(", ", ftos(f2), ", ", ftos(f3), ", ", ftos(f4), ");\n"))); - dprint(" ^--: stringcount: ", ftos(stringcount), ", floatcount: ", ftos(floatcount), ".\n"); + CHECKARG_TYPENAME(INFO) + CHECKARG_TYPENAME(CENTER) + CHECKARG_TYPENAME(WEAPON) + CHECKARG_TYPENAME(DEATH) + default: { checkargs = sprintf("Improper type: %d!", checkargs, net_type); break; } + } + #undef CHECKARG_TYPENAME + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Local_Notification: %s\n", checkargs)); return; } + + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Local_Notification: Could not find notification entity!\n"); return; } + if not(notif.nent_enabled) { print("Local_Notification: Entity was disabled...\n"); return; } - if((stringcount + floatcount) > count) { backtrace(strcat("Not enough arguments for Local_Notification! ", strcat("stringcount(", ftos(stringcount), ") + floatcount(", ftos(floatcount), ")"), " > count(", ftos(count), ").\nCheck the notification definition and the function call for accuracy...?\n")); return; } - else if((stringcount + floatcount) < count) { backtrace(strcat("Too many arguments for Local_Notification! ", strcat("stringcount(", ftos(stringcount), ") + floatcount(", ftos(floatcount), ")"), " < count(", ftos(count), ").\nCheck the notification definition and the function call for accuracy...?\n")); return; } + if((notif.nent_stringcount + notif.nent_floatcount) > count) + { + backtrace(sprintf( + strcat( + "Not enough arguments for Local_Notification! ", + "stringcount(%d) + floatcount(%d) > count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + notif.nent_stringcount, notif.nent_floatcount, count)); + return; + } + else if((notif.nent_stringcount + notif.nent_floatcount) < count) + { + backtrace(sprintf( + strcat( + "Too many arguments for Local_Notification! ", + "stringcount(%d) + floatcount(%d) < count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + notif.nent_stringcount, notif.nent_floatcount, count)); + return; + } - switch(net_type) + string s1 = ((0 < notif.nent_stringcount) ? ...(0, string) : ""); + string s2 = ((1 < notif.nent_stringcount) ? ...(1, string) : ""); + string s3 = ((2 < notif.nent_stringcount) ? ...(2, string) : ""); + string s4 = ((3 < notif.nent_stringcount) ? ...(3, string) : ""); + float f1 = ((0 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 0), float) : 0); + float f2 = ((1 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 1), float) : 0); + float f3 = ((2 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 2), float) : 0); + float f4 = ((3 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 3), float) : 0); + + #ifdef NOTIFICATIONS_DEBUG + dprint( + sprintf("Local_Notification(%d, %s, %s, %s);\n", + net_type, + notif.nent_name, + sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4), + sprintf("%d, %d, %d, %d", f1, f2, f3, f4) + ) + ); + #endif + + switch(net_type) + { + case MSG_INFO: + { + print( + Local_Notification_sprintf( + notif.nent_string, + notif.nent_args, + s1, s2, s3, s4, + f1, f2, f3, f4) + ); + #ifdef CSQC + if(notif.nent_icon != "") + { + Local_Notification_HUD_Notify_Push( + notif.nent_icon, + notif.nent_hudargs, + s1, s2, s3, s4); + } + #endif + break; + } + + #ifdef CSQC + case MSG_CENTER: + { + centerprint_generic( + notif.nent_cpid, + Local_Notification_sprintf( + notif.nent_string, + notif.nent_args, + s1, s2, s3, s4, + f1, f2, f3, f4), + 0, 0); + break; + } + #endif + + case MSG_WEAPON: + case MSG_DEATH: { - case MSG_INFO: + if(notif.nent_msginfo) + if(notif.nent_msginfo.nent_enabled) { - #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \ - case name: { CHECK_AUTOCVAR(name) \ - { \ - tmp_s = normal_or_gentle(normal, gentle); if(tmp_s != "") \ - { \ - if(substring(tmp_s, (strlen(tmp_s) - 1), 1) == "\n") { print(sprintf(CCR(tmp_s), args)); } \ - else { backtrace(strcat("^1MISSING/BROKEN NEW LINE AT END OF NOTIFICATION: ^7net_type = MSG_INFO, net_name = ", Get_Field_Value(F_NAME, net_type, net_name), (GENTLE ? ", GENTLE string" : ", NORMAL string"), ".\n")); } \ - #ifdef CSQC \ - tmp_s = icon; if(tmp_s != "") { HUD_Notify_Push(icon, hudargs); } \ - #endif \ - } \ - else { backtrace(strcat("^1EMPTY NOTIFICATION: ^7net_type = MSG_INFO, net_name = ", Get_Field_Value(F_NAME, net_type, net_name), ".\n")); } \ - } break; } - - switch(net_name) - { - MSG_INFO_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_INFO, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_INFO_NOTIF - break; + Local_Notification_WOVA( + MSG_INFO, + notif.nent_msginfo.nent_id, + notif.nent_msginfo.nent_stringcount, + notif.nent_msginfo.nent_floatcount, + s1, s2, s3, s4, + f1, f2, f3, f4); } #ifdef CSQC - case MSG_CENTER: + if(notif.nent_msgcenter) + if(notif.nent_msgcenter.nent_enabled) { - #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \ - case name: { CHECK_AUTOCVAR(name) \ - { \ - tmp_s = normal_or_gentle(normal, gentle); if(tmp_s != "") { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(tmp_s), args), durcnt); } \ - else { backtrace(strcat("^1EMPTY NOTIFICATION: ^7net_type = MSG_CENTER, net_name = ", Get_Field_Value(F_NAME, net_type, net_name), ".\n")); } \ - } break; } - - switch(net_name) - { - MSG_CENTER_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_CENTER, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_CENTER_NOTIF - break; + Local_Notification_WOVA( + MSG_CENTER, + notif.nent_msgcenter.nent_id, + notif.nent_msgcenter.nent_stringcount, + notif.nent_msgcenter.nent_floatcount, + s1, s2, s3, s4, + f1, f2, f3, f4); } #endif - case MSG_WEAPON: - { - #define MSG_WEAPON_NOTIF(name,infoname,centername) \ - case name: { CHECK_AUTOCVAR(name) \ - { \ - #if infoname != NO_MSG \ - Local_Notification_Without_VarArgs(MSG_INFO, infoname, \ - stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), \ - stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), \ - s1, s2, s3, s4, f1, f2, f3, f4); \ - #endif \ - #ifdef CSQC \ - #if centername != NO_MSG \ - Local_Notification_Without_VarArgs(MSG_CENTER, centername, \ - stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername)), \ - stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)), \ - s1, s2, s3, s4, f1, f2, f3, f4); \ - #endif \ - #endif \ - } break; } - - switch(net_name) - { - MSG_WEAPON_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_WEAPON, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_WEAPON_NOTIF - break; - } - case MSG_DEATH: - { - #define MSG_DEATH_NOTIF(name,infoname,centername) \ - case name: { CHECK_AUTOCVAR(name) \ - { \ - #if infoname != NO_MSG \ - Local_Notification_Without_VarArgs(MSG_INFO, infoname, \ - stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), \ - stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), \ - s1, s2, s3, s4, f1, f2, f3, f4); \ - #endif \ - #ifdef CSQC \ - #if centername != NO_MSG \ - Local_Notification_Without_VarArgs(MSG_CENTER, centername, \ - stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername)), \ - stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)), \ - s1, s2, s3, s4, f1, f2, f3, f4); \ - #endif \ - #endif \ - } break; } - - switch(net_name) - { - MSG_DEATH_NOTIFICATIONS - default: { backtrace(strcat("^1NOTIFICATION HAD NO MATCH: ^7net_type = MSG_DEATH, net_name = ", ftos(net_name), ".\n")); break; } - } - - #undef MSG_DEATH_NOTIF - break; - } + break; } } - else { backtrace("Incorrect usage of Local_Notification!\n"); } } -void Local_Notification_Without_VarArgs(float net_type, float net_name, float stringcount, float floatcount, string s1, string s2, string s3, string s4, float f1, float f2, float f3, float f4) +// WOVA = Without Variable Arguments +void Local_Notification_WOVA(float net_type, float net_name, + float stringcount, float floatcount, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4) { - #define VARITEM(stringc,floatc,args) if((stringcount == stringc) && (floatcount == floatc)) { Local_Notification(net_type, net_name, args); return; } + #define VARITEM(stringc,floatc,args) \ + if((stringcount == stringc) && (floatcount == floatc)) \ + { Local_Notification(net_type, net_name, args); return; } EIGHT_VARS_TO_VARARGS_VARLIST #undef VARITEM - Local_Notification(net_type, net_name); // some notifications don't have any arguments at all } @@ -294,43 +362,118 @@ void Read_Notification(float is_new) float net_type = ReadByte(); float net_name = ReadShort(); - float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name)); - float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name)); - - string s1 = ((stringcount >= 1) ? ReadString() : NO_STR_ARG); - string s2 = ((stringcount >= 2) ? ReadString() : NO_STR_ARG); - string s3 = ((stringcount >= 3) ? ReadString() : NO_STR_ARG); - string s4 = ((stringcount == 4) ? ReadString() : NO_STR_ARG); - float f1 = ((floatcount >= 1) ? ReadLong() : NO_FL_ARG); - float f2 = ((floatcount >= 2) ? ReadLong() : NO_FL_ARG); - float f3 = ((floatcount >= 3) ? ReadLong() : NO_FL_ARG); - float f4 = ((floatcount == 4) ? ReadLong() : NO_FL_ARG); - - if(is_new) { Local_Notification_Without_VarArgs(net_type, net_name, stringcount, floatcount, s1, s2, s3, s4, f1, f2, f3, f4); } - else { print("received old notification? net_name = ", Get_Field_Value(F_NAME, net_type, net_name), ".\n"); } + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { print("Read_Notification: Could not find notification entity!\n"); return; } + + string s1 = ((0 < notif.nent_stringcount) ? ReadString() : ""); + string s2 = ((1 < notif.nent_stringcount) ? ReadString() : ""); + string s3 = ((2 < notif.nent_stringcount) ? ReadString() : ""); + string s4 = ((3 < notif.nent_stringcount) ? ReadString() : ""); + float f1 = ((0 < notif.nent_floatcount) ? ReadLong() : 0); + float f2 = ((1 < notif.nent_floatcount) ? ReadLong() : 0); + float f3 = ((2 < notif.nent_floatcount) ? ReadLong() : 0); + float f4 = ((3 < notif.nent_floatcount) ? ReadLong() : 0); + + #ifdef NOTIFICATIONS_DEBUG + dprint(sprintf("Read_Notification(%d) at %f: net_name = %s.\n", is_new, time, notif.nent_name)); + #endif + + if(is_new) + { + Local_Notification_WOVA( + net_type, net_name, + notif.nent_stringcount, + notif.nent_floatcount, + s1, s2, s3, s4, + f1, f2, f3, f4); + } } #endif #ifdef SVQC -void Notification_Remove() +void Net_Notification_Remove() { float i; for(i = 0; i < 4; ++i) { if(self.nent_strings[i]) { strunzone(self.nent_strings[i]); } } remove(self); } -float Write_Notification(entity client, float sf) +float Net_Write_Notification(entity client, float sf) { float i, send = FALSE; switch(self.nent_broadcast) { - case NOTIF_ONE: { if((client == self.nent_client) || (client.classname == STR_SPECTATOR && client.enemy == self.nent_client)) { send = TRUE; } break; } - case NOTIF_ONE_ONLY: { if(client == self.nent_client) { send = TRUE; } break; } - case NOTIF_TEAM: { if((client.team == self.nent_client.team) || (client.classname == STR_SPECTATOR && client.enemy.team == self.nent_client.team)) { send = TRUE; } break; } - case NOTIF_TEAM_EXCEPT: { if(((client != self.nent_client) && (client.team == self.nent_client.team) && !(client.classname == STR_SPECTATOR && client.enemy == self.nent_client))) { send = TRUE; } break; } - case NOTIF_ANY: { send = TRUE; break; } - case NOTIF_ANY_EXCEPT: { if((client != self.nent_client) && !(client.classname == STR_SPECTATOR && client.enemy == self.nent_client)) { send = TRUE; } break; } + case NOTIF_ONE: // send to one client and their spectator + { + if( + (client == self.nent_client) + || + ( + (client.classname == STR_SPECTATOR) + && + (client.enemy == self.nent_client) + ) + ) { send = TRUE; } + break; + } + case NOTIF_ONE_ONLY: // send ONLY to one client + { + if(client == self.nent_client) { send = TRUE; } + break; + } + case NOTIF_TEAM: // send only to X team and their spectators + { + if( + (client.team == self.nent_client.team) + || + ( + (client.classname == STR_SPECTATOR) + && + (client.enemy.team == self.nent_client.team) + ) + ) { send = TRUE; } + break; + } + case NOTIF_TEAM_EXCEPT: // send only to X team and their spectators, except for Y person and their spectators + { + if( + (client != self.nent_client) + && + ( + (client.team == self.nent_client.team) + || + ( + (client.classname == STR_SPECTATOR) + && + ( + (client.enemy != self.nent_client) + && + (client.enemy.team == self.nent_client.team) + ) + ) + ) + ) { send = TRUE; } + break; + } + case NOTIF_ANY: // send to everyone + { + send = TRUE; + break; + } + case NOTIF_ANY_EXCEPT: // send to everyone except X person and their spectators + { + if( + (client != self.nent_client) + && + !( + (client.classname == STR_SPECTATOR) + && + (client.enemy == self.nent_client) + ) + ) { send = TRUE; } + break; + } default: { send = FALSE; break; } } @@ -346,57 +489,145 @@ float Write_Notification(entity client, float sf) return send; } -void Send_Notification(float broadcast, entity client, float net_type, float net_name, ...count) +void Send_Notification(float broadcast, entity client, + float net_type, float net_name, ...count) { - if(broadcast && net_type && net_name) + // check supplied broadcast, target, type, and name for errors + string checkargs = ""; + #define CHECKARG_TYPENAME(type) case MSG_##type##: \ + { if(!net_name || (net_name > NOTIF_##type##_COUNT)) \ + { checkargs = sprintf("Improper name: %d!", net_name); } break; } + switch(net_type) { - float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name)); - float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name)); - float i; - - dprint("Send_Notification(", ftos(broadcast), ", ", ftos(net_type), ", ", Get_Field_Value(F_NAME, net_type, net_name), strcat(", ", ftos(count), ");\n")); - dprint(" ^--: stringcount: ", ftos(stringcount), ", floatcount: ", ftos(floatcount), ".\n"); - - if((stringcount + floatcount) > count) { backtrace(strcat("Not enough arguments for Send_Notification! ", strcat("stringcount(", ftos(stringcount), ") + floatcount(", ftos(floatcount), "),"), " > count(", ftos(count), ").\nCheck the notification definition and the function call for accuracy...?\n")); return; } - else if((stringcount + floatcount) < count) { backtrace(strcat("Too many arguments for Send_Notification! ", strcat("stringcount(", ftos(stringcount), ") + floatcount(", ftos(floatcount), "),"), " < count(", ftos(count), ").\nCheck the notification definition and the function call for accuracy...?\n")); return; } - - entity notif = spawn(); - notif.nent_broadcast = broadcast; - notif.nent_client = client; - notif.nent_net_type = net_type; - notif.nent_net_name = net_name; - notif.nent_stringcount = stringcount; - notif.nent_floatcount = floatcount; - for(i = 0; i < stringcount; ++i) { notif.nent_strings[i] = strzone(...(i, string)); } - for(i = 0; i < floatcount; ++i) { notif.nent_floats[i] = ...((stringcount + i), float); } + CHECKARG_TYPENAME(INFO) + CHECKARG_TYPENAME(CENTER) + CHECKARG_TYPENAME(WEAPON) + CHECKARG_TYPENAME(DEATH) + default: { checkargs = sprintf("Improper type: %d!", checkargs, net_type); break; } + } + #undef CHECKARG_TYPENAME + if(checkargs != "") { checkargs = strcat(checkargs, " "); } + switch(broadcast) + { + case NOTIF_ONE: + case NOTIF_ONE_ONLY: + { + if(IS_NOT_A_CLIENT(client)) + { checkargs = sprintf("%sNo client provided!", checkargs); } + break; + } - notif.think = Notification_Remove; - notif.nextthink = (time + 0.5); - - Net_LinkEntity(notif, FALSE, 0, Write_Notification); - - if(!server_is_local) + case NOTIF_ANY_EXCEPT: + { + if(IS_NOT_A_CLIENT(client)) + { checkargs = sprintf("%sException can't be a non-client!", checkargs); } + break; + } + + case NOTIF_ANY: + { + if(client) + { checkargs = sprintf("%sEntity provided when world was required!", checkargs); } + break; + } + + case NOTIF_TEAM: + case NOTIF_TEAM_EXCEPT: { - Local_Notification_Without_VarArgs(net_type, net_name, stringcount, floatcount, IFSTR(0), IFSTR(1), IFSTR(2), IFSTR(3), IFFL(0), IFFL(1), IFFL(2), IFFL(3)); + if not(teamplay) { checkargs = sprintf("%sTeamplay not active!", checkargs); } + else if(IS_NOT_A_CLIENT(client)) + { + if(broadcast == NOTIF_TEAM) { checkargs = sprintf("%sNo client provided!", checkargs); } + else { checkargs = sprintf("%sException can't be a non-client!", checkargs); } + } + break; } + + default: { checkargs = sprintf("%sImproper broadcast: %d!", checkargs, broadcast); break; } } - else { backtrace("Incorrect usage of Send_Notification!\n"); } -} + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Send_Notification: %s\n", checkargs)); return; } -void Send_Notification_Without_VarArgs(float broadcast, entity client, float net_type, float net_name, float stringcount, float floatcount, string s1, string s2, string s3, string s4, float f1, float f2, float f3, float f4) -{ - #define VARITEM(stringc,floatc,args) if((stringcount == stringc) && (floatcount == floatc)) { Send_Notification(broadcast, client, net_type, net_name, args); return; } - EIGHT_VARS_TO_VARARGS_VARLIST - #undef VARITEM + // retreive counts for the arguments of this notification + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Send_Notification: Could not find notification entity!\n"); return; } - Send_Notification(broadcast, client, net_type, net_name); // some notifications don't have any arguments at all + if((notif.nent_stringcount + notif.nent_floatcount) > count) + { + backtrace(sprintf( + strcat( + "Not enough arguments for Send_Notification! ", + "stringcount(%d) + floatcount(%d) > count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + notif.nent_stringcount, notif.nent_floatcount, count)); + return; + } + else if((notif.nent_stringcount + notif.nent_floatcount) < count) + { + backtrace(sprintf( + strcat( + "Too many arguments for Send_Notification! ", + "stringcount(%d) + floatcount(%d) < count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + notif.nent_stringcount, notif.nent_floatcount, count)); + return; + } + + #ifdef NOTIFICATIONS_DEBUG + dprint( + sprintf("Send_Notification(%d, %d, %s, stringcount: %d, floatcount: %d, varargs: %d);\n", + broadcast, + net_type, + notif.nent_name, + notif.nent_stringcount, + notif.nent_floatcount, + count + ) + ); + #endif + + entity net_notif = spawn(); + net_notif.nent_broadcast = broadcast; + net_notif.nent_client = client; + net_notif.nent_net_type = net_type; + net_notif.nent_net_name = net_name; + net_notif.nent_stringcount = notif.nent_stringcount; + net_notif.nent_floatcount = notif.nent_floatcount; + + float i; + for(i = 0; i < net_notif.nent_stringcount; ++i) { net_notif.nent_strings[i] = strzone(...(i, string)); } + for(i = 0; i < net_notif.nent_floatcount; ++i) { net_notif.nent_floats[i] = ...((net_notif.nent_stringcount + i), float); } + + net_notif.think = Net_Notification_Remove; + net_notif.nextthink = (time + 0.5); + + Net_LinkEntity(net_notif, FALSE, 0, Net_Write_Notification); + + if((!server_is_local) && (broadcast == NOTIF_ANY || broadcast == NOTIF_ANY_EXCEPT) && (net_type != MSG_CENTER)) + { + Local_Notification_WOVA( + net_type, net_name, + notif.nent_stringcount, + notif.nent_floatcount, + IFSTR(0), IFSTR(1), IFSTR(2), IFSTR(3), + IFFL(0), IFFL(1), IFFL(2), IFFL(3)); + } } -void Send_Notification_Legacy_Wrapper(float broadcast, entity client, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3) +// WOVA = Without Variable Arguments +void Send_Notification_WOVA(float broadcast, entity client, + float net_type, float net_name, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4) { - float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name)); - float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name)); - Send_Notification_Without_VarArgs(broadcast, client, net_type, net_name, stringcount, floatcount, s1, s2, NO_STR_ARG, NO_STR_ARG, f1, f2, f3, NO_FL_ARG); + entity notif = Get_Notif_Ent(net_type, net_name); + #define VARITEM(stringc,floatc,args) \ + if((notif.nent_stringcount == stringc) && (notif.nent_floatcount == floatc)) \ + { Send_Notification(broadcast, client, net_type, net_name, args); return; } + EIGHT_VARS_TO_VARARGS_VARLIST + #undef VARITEM + Send_Notification(broadcast, client, net_type, net_name); // some notifications don't have any arguments at all } @@ -422,9 +653,4 @@ void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, }); } } -void Send_CSQC_Centerprint_Generic_Expire(entity e, float id) -{ - Send_CSQC_Centerprint_Generic(e, id, "", 1, 0); -} #endif // ifdef SVQC -#endif // ifndef MENUQC