X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fnotifications.qc;h=5653a6d9a946e9e8fcc20e5c8641b2660813fd62;hb=bbaf4c7bfcf77ccbb4b062be874e87108beda03e;hp=9b19d169b8114d218defe73750e80e2ec03f4072;hpb=0c5ce37b4f1cd9d271b7e7fb3e3e3b296034d87a;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/notifications.qc b/qcsrc/common/notifications.qc index 9b19d169b..5653a6d9a 100644 --- a/qcsrc/common/notifications.qc +++ b/qcsrc/common/notifications.qc @@ -3,72 +3,98 @@ // 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) +string Get_Notif_TypeName(float net_type) { - #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) switch(field) { \ - case F_NAME: { return VAR_TO_TEXT(name); } \ - case F_STRNUM: { return ftos(strnum); } \ - case F_FLNUM: { return ftos(flnum); } } - - #define CLPSE_GETVALUE(name,type,field) \ - #if name != NO_MSG \ - stof(Get_Field_Value(field, type, name)) \ - #else \ - 0 \ - #endif + switch(net_type) + { + case MSG_INFO: return "MSG_INFO"; + case MSG_CENTER: return "MSG_CENTER"; + case MSG_WEAPON: return "MSG_WEAPON"; + case MSG_DEATH: return "MSG_DEATH"; + } + backtrace(sprintf("Get_Notif_TypeName(%d): Improper net type!\n", net_type)); + return "your ass"; +} +entity Get_Notif_Ent(float net_type, float net_name) +{ switch(net_type) { - case MSG_INFO: + 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]; + } + backtrace(sprintf("Get_Notif_Ent(%d, %d): Improper net type!\n", net_type, net_name)); + return world; +} + +string Notification_CheckArgs_TypeName(float net_type, float 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) + { + 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 + return checkargs; +} + +#ifdef SVQC +string Notification_CheckArgs(float broadcast, entity client, float net_type, float net_name) +{ + // check supplied broadcast, target, type, and name for errors + string checkargs = Notification_CheckArgs_TypeName(net_type, net_name); + if(checkargs != "") { checkargs = strcat(checkargs, " "); } + switch(broadcast) + { + case NOTIF_ONE: + case NOTIF_ONE_ONLY: { - #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) case name: { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } - - NOTIF_SWITCH_LIST(MSG_INFO, net_name, return "") - - #undef MSG_INFO_NOTIF + if(IS_NOT_A_CLIENT(client)) + { checkargs = sprintf("%sNo client provided!", checkargs); } break; } - case MSG_CENTER: + + case NOTIF_ANY_EXCEPT: { - #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) case name: { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } - - NOTIF_SWITCH_LIST(MSG_CENTER, net_name, return "") - - #undef MSG_CENTER_NOTIF + if(IS_NOT_A_CLIENT(client)) + { checkargs = sprintf("%sException can't be a non-client!", checkargs); } break; } - case MSG_WEAPON: + + case NOTIF_ANY: { - #define MSG_WEAPON_NOTIF(name,infoname,centername) case name: { GET_FIELD_VALUE_OUTPUT(field,name, \ - max(CLPSE_GETVALUE(infoname, MSG_INFO, F_STRNUM), CLPSE_GETVALUE(centername, MSG_CENTER, F_STRNUM)), \ - max(CLPSE_GETVALUE(infoname, MSG_INFO, F_FLNUM), CLPSE_GETVALUE(centername, MSG_CENTER, F_FLNUM))) } - - NOTIF_SWITCH_LIST(MSG_WEAPON, net_name, return "") - - #undef MSG_WEAPON_NOTIF + if(client) + { checkargs = sprintf("%sEntity provided when world was required!", checkargs); } break; } - case MSG_DEATH: + + case NOTIF_TEAM: + case NOTIF_TEAM_EXCEPT: { - #define MSG_DEATH_NOTIF(name,infoname,centername) case name: { GET_FIELD_VALUE_OUTPUT(field,name, \ - max(CLPSE_GETVALUE(infoname, MSG_INFO, F_STRNUM), CLPSE_GETVALUE(centername, MSG_CENTER, F_STRNUM)), \ - max(CLPSE_GETVALUE(infoname, MSG_INFO, F_FLNUM), CLPSE_GETVALUE(centername, MSG_CENTER, F_FLNUM))) } - - NOTIF_SWITCH_LIST(MSG_DEATH, net_name, return "") - - #undef MSG_DEATH_NOTIF + 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; } } - - #undef GET_FIELD_VALUE_OUTPUT - #undef CLPSE_GETVALUE - return ""; + return checkargs; } -#endif // ifndef MENUQC - +#endif // =============================== // Frontend Notification Pushing @@ -76,171 +102,351 @@ 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"); + + // 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); + } - #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 + 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_location 0 \"Append location information to MSG_INFO death/kill messages\"\n"); + NOTIF_WRITE("seta notification_show_location_string \"\" \"Replacement string piped into sprintf, so you can do different messages like this: ' at the %s' or ' (near %s)'\"\n"); + NOTIF_WRITE("seta notification_show_sprees 1 \"Print information about sprees in death/kill messages\"\n"); + NOTIF_WRITE("seta notification_show_sprees_center 1 \"Show spree information in MSG_CENTER messages... 0 = off, 1 = target (but only for first victim) and attacker\"\n"); + NOTIF_WRITE("seta notification_show_sprees_center_specialonly 1 \"Don't show spree information in MSG_CENTER messages if it isn't an achievement\"\n"); + NOTIF_WRITE("seta notification_show_sprees_info 3 \"Show spree information in MSG_INFO messages... 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker\"\n"); + NOTIF_WRITE("seta notification_show_sprees_info_newline 0 \"Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself\"\n"); + NOTIF_WRITE("seta notification_show_sprees_info_specialonly 1 \"Don't show attacker spree information in MSG_INFO messages if it isn't an achievement\"\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("seta notification_lifetime_runtime 0.5 \"Amount of time that notification entities last on the server during runtime (In seconds)\"\n"); + NOTIF_WRITE("seta notification_lifetime_mapload 10 \"Amount of time that notification entities last immediately at mapload (in seconds) to help prevent notifications from being lost on early init (like gamestart countdown)\"\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 - // icon - if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); } - killnotify_icon[kn_index] = strzone(icon); +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] = ""; } - // attacker - if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); } - killnotify_attackers[kn_index] = strzone(attacker); + string tmp_s; - // victim - if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); } - killnotify_victims[kn_index] = strzone(victim); + 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_SV) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif \ + #else \ + #if (prog != ARG_CS) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: 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]); } -#endif // ifdef CSQC -void Local_Notification(float net_type, float net_name, ...count) +#ifdef CSQC +void Local_Notification_HUD_Notify_Push(string icon, string hudargs, string s1, string s2, string s3, string s4) { - if(net_type && net_name) + string selected; + float sel_num; + arg_slot[0] = ""; arg_slot[1] = ""; + + for(sel_num = 0;(hudargs != "");) { - 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); - - 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"); + 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_CS_SV_HA) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: NOTIF_HIT_UNKNOWN(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push") + } + } + HUD_Notify_Push(icon, arg_slot[0], arg_slot[1]); +} - 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; } +void Local_Notification_centerprint_generic(string input, string durcnt, float cpid, float f1, float f2) +{ + string selected; + float sel_num; + arg_slot[0] = ""; arg_slot[1] = ""; - switch(net_type) + for(sel_num = 0;(durcnt != "");) + { + selected = car(durcnt); durcnt = cdr(durcnt); + NOTIF_HIT_MAX(NOTIF_MAX_DURCNT, "Local_Notification_centerprint_generic") + switch(strtolower(selected)) { - case MSG_INFO: + #define ARG_CASE(prog,selected,result) \ + #if (prog == ARG_CS_SV_DC) || (prog == ARG_DC) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: { - #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \ - case name: { CHECK_AUTOCVAR(name) \ - { \ - print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); \ - #ifdef CSQC \ - if(icon != "") { HUD_Notify_Push(icon, hudargs); } \ - #endif \ - } return; } - - NOTIF_SWITCH_LIST(MSG_INFO, net_name, return) - - #undef MSG_INFO_NOTIF + if(ftos(stof(selected)) != "") { arg_slot[sel_num] = selected; ++sel_num; } + else { NOTIF_HIT_UNKNOWN(NOTIF_MAX_DURCNT, "Local_Notification_centerprint_generic") } break; } - #ifdef CSQC - case MSG_CENTER: + } + } + centerprint_generic(cpid, input, stof(arg_slot[0]), stof(arg_slot[1])); +} +#endif + +void Local_Notification(float net_type, float net_name, ...count) +{ + // check supplied type and name for errors + string checkargs = Notification_CheckArgs_TypeName(net_type, net_name); + 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; } + + #ifdef NOTIFICATIONS_DEBUG + if not(notif.nent_enabled) { dprint(sprintf("Local_Notification(%s, %s): Entity was disabled...\n", Get_Notif_TypeName(net_type), notif.nent_name)); return; } + #endif + + if((notif.nent_stringcount + notif.nent_floatcount) > count) + { + backtrace(sprintf( + strcat( + "Not enough arguments for Local_Notification(%s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) > count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + Get_Notif_TypeName(net_type), notif.nent_name, 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(%s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) < count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + Get_Notif_TypeName(net_type), notif.nent_name, notif.nent_stringcount, notif.nent_floatcount, count)); + return; + } + + 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(%s, %s, %s, %s);\n", + Get_Notif_TypeName(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 != "") { - #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \ - case name: { CHECK_AUTOCVAR(name) \ - { \ - centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); \ - } return; } - - NOTIF_SWITCH_LIST(MSG_CENTER, net_name, return) - - #undef MSG_CENTER_NOTIF - break; - } - #endif - case MSG_WEAPON: + Local_Notification_HUD_Notify_Push( + notif.nent_icon, + notif.nent_hudargs, + s1, s2, s3, s4); + } + #endif + break; + } + + #ifdef CSQC + case MSG_CENTER: + { + Local_Notification_centerprint_generic( + Local_Notification_sprintf( + notif.nent_string, + notif.nent_args, + s1, s2, s3, s4, + f1, f2, f3, f4), + notif.nent_durcnt, + notif.nent_cpid, + f1, f2); + break; + } + #endif + + case MSG_WEAPON: + case MSG_DEATH: + { + if(notif.nent_msginfo) + if(notif.nent_msginfo.nent_enabled) { - #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 \ - } return; } - - NOTIF_SWITCH_LIST(MSG_WEAPON, net_name, return) - - #undef MSG_WEAPON_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); } - case MSG_DEATH: + #ifdef CSQC + if(notif.nent_msgcenter) + if(notif.nent_msgcenter.nent_enabled) { - #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 \ - } return; } - - NOTIF_SWITCH_LIST(MSG_DEATH, net_name, return) - - #undef MSG_DEATH_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 + 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 } @@ -255,43 +461,134 @@ 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)); + if(net_type == MSG_CENTER_KILL) + { + if(is_new) + { + if(net_name == 0) { reset_centerprint_messages(); } + else + { + entity notif = Get_Notif_Ent(MSG_CENTER, net_name); + if not(notif) { backtrace("Read_Notification: Could not find notification entity!\n"); return; } + centerprint_generic(notif.nent_cpid, "", 0, 0); + } + } + } + else + { + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Read_Notification: Could not find notification entity!\n"); return; } - 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); + #ifdef NOTIFICATIONS_DEBUG + dprint(sprintf("Read_Notification(%d) at %f: net_type = %s, net_name = %s\n", is_new, time, Get_Notif_TypeName(net_type), notif.nent_name)); + #endif - 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"); } + 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); + + 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; } } @@ -307,97 +604,162 @@ float Write_Notification(entity client, float sf) return send; } -string Send_Notification_CheckTarget(float broadcast, entity client) +void Kill_Notification(float broadcast, entity client, float net_type, float net_name) { - switch(broadcast) + string checkargs = Notification_CheckArgs(broadcast, client, net_type, 1); + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Kill_Notification: %s\n", checkargs)); return; } + + entity notif; + + // if this is a centerprint, we must tell the client + // to kill the cpid in the centerprint queue + if(net_type == MSG_CENTER) { - case NOTIF_ONE: - case NOTIF_ONE_ONLY: - { - if(clienttype(client) != CLIENTTYPE_REAL) { return "No real client provided!"; } - else { return ""; } - } - - case NOTIF_TEAM: - case NOTIF_TEAM_EXCEPT: - { - if not(teamplay) { return "Teamplay not active!"; } - else if(clienttype(client) == CLIENTTYPE_NOTACLIENT) { return "No real client provided!"; } - else if((broadcast == NOTIF_TEAM_EXCEPT) && (clienttype(client) != CLIENTTYPE_REAL)) { return "Exception can't be a non-real client!"; } - else { return ""; } - } - - case NOTIF_ANY_EXCEPT: - { - if(clienttype(client) != CLIENTTYPE_REAL) { return "Exception can't be a non-real client!"; } - else { return ""; } - } + notif = spawn(); + notif.classname = "net_kill_notification"; + notif.nent_broadcast = broadcast; + notif.nent_client = client; + notif.nent_net_type = MSG_CENTER_KILL; + notif.nent_net_name = net_name; + Net_LinkEntity(notif, FALSE, autocvar_notification_lifetime_runtime, Net_Write_Notification); + } - case NOTIF_ANY: + for(notif = world; (notif = find(notif, classname, "net_notification"));) + { + // now kill the old send notification entity + if(notif.nent_net_type == net_type) { - if(client) { return "Entity provided when world was required!"; } - else { return ""; } + if(net_name) + { if(notif.nent_net_name == net_name) { notif.think(); } } + else + { notif.think(); } + + #ifdef NOTIFICATIONS_DEBUG + print(sprintf("killed '%s'\n", notif.classname)); + #endif } } - - return strcat("Improper broadcast type: ", ftos(broadcast), "!"); } -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) { - string checktarget = Send_Notification_CheckTarget(broadcast, client); - - if((checktarget == "") && net_type && net_name) - { - 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; + // check supplied broadcast, target, type, and name for errors + string checkargs = Notification_CheckArgs(broadcast, client, net_type, net_name); + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Send_Notification: %s\n", checkargs)); return; } - 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"); + // 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; } - 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; } + if((notif.nent_stringcount + notif.nent_floatcount) > count) + { + backtrace(sprintf( + strcat( + "Not enough arguments for Send_Notification(%d, %s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) > count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + broadcast, Get_Notif_TypeName(net_type), notif.nent_name, 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(%d, %s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) < count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + broadcast, Get_Notif_TypeName(net_type), notif.nent_name, notif.nent_stringcount, notif.nent_floatcount, count)); + 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); } - - notif.think = Notification_Remove; - notif.nextthink = (time + 0.5); + #ifdef NOTIFICATIONS_DEBUG + 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); + dprint( + sprintf("Send_Notification(%d, %s, %s, %s, %s - %d %d);\n", + broadcast, + Get_Notif_TypeName(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), + notif.nent_stringcount, notif.nent_floatcount + ) + ); + #endif + + entity net_notif = spawn(); + net_notif.classname = "net_notification"; + 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_LinkEntity(notif, FALSE, 0, Write_Notification); + net_notif.think = Net_Notification_Remove; + net_notif.nextthink = + ((time > autocvar_notification_lifetime_mapload) + ? + (time + autocvar_notification_lifetime_runtime) + : + autocvar_notification_lifetime_mapload + ); - if((!server_is_local) && (broadcast == NOTIF_ANY || broadcast == NOTIF_ANY_EXCEPT) && (net_type != MSG_CENTER)) - { - 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)); - } + Net_LinkEntity(net_notif, FALSE, 0, Net_Write_Notification); + + if(server_is_dedicated && (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)); } - else { backtrace(strcat("Incorrect usage of Send_Notification: ", checktarget, "\n")); } } -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; } +// 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) +{ + entity notif = Get_Notif_Ent(net_type, net_name); + + #ifdef NOTIFICATIONS_DEBUG + dprint( + sprintf("Send_Notification_WOVA(%d, %s, %s, %s, %s - %d %d);\n", + broadcast, + Get_Notif_TypeName(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), + notif.nent_stringcount, notif.nent_floatcount + ) + ); + #endif + + #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 } -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) -{ - 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); -} - // ============================= // LEGACY NOTIFICATION SYSTEMS @@ -421,9 +783,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