]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/trigger/magicear.qc
Merge branch 'terencehill/menu_fixes' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / trigger / magicear.qc
1 #ifdef SVQC
2 float magicear_matched;
3 float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
4 string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
5 {SELFPARAM();
6         float domatch, dotrigger, matchstart, l;
7         string s, msg;
8         string savemessage;
9
10         magicear_matched = false;
11
12         dotrigger = ((IS_PLAYER(source)) && (!IS_DEAD(source)) && ((ear.radius == 0) || (vdist(source.origin - ear.origin, <=, ear.radius))));
13         domatch = ((ear.spawnflags & 32) || dotrigger);
14
15         if (!domatch)
16                 return msgin;
17
18         if (!msgin)
19         {
20                 // we are in TUBA mode!
21                 if (!(ear.spawnflags & 256))
22                         return msgin;
23
24                 if(!W_Tuba_HasPlayed(source, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z))
25                         return msgin;
26
27                 magicear_matched = true;
28
29                 if(dotrigger)
30                 {
31                         savemessage = self.message;
32                         self.message = string_null;
33                         SUB_UseTargets(ear, source, NULL);
34                         self.message = savemessage;
35                 }
36
37                 if(ear.netname != "")
38                         return ear.netname;
39
40                 return msgin;
41         }
42
43         if(ear.spawnflags & 256) // ENOTUBA
44                 return msgin;
45
46         if(privatesay)
47         {
48                 if(ear.spawnflags & 4)
49                         return msgin;
50         }
51         else
52         {
53                 if(!teamsay)
54                         if(ear.spawnflags & 1)
55                                 return msgin;
56                 if(teamsay > 0)
57                         if(ear.spawnflags & 2)
58                                 return msgin;
59                 if(teamsay < 0)
60                         if(ear.spawnflags & 8)
61                                 return msgin;
62         }
63
64         matchstart = -1;
65         l = strlen(ear.message);
66
67         if(ear.spawnflags & 128)
68                 msg = msgin;
69         else
70                 msg = strdecolorize(msgin);
71
72         if(substring(ear.message, 0, 1) == "*")
73         {
74                 if(substring(ear.message, -1, 1) == "*")
75                 {
76                         // two wildcards
77                         // as we need multi-replacement here...
78                         s = substring(ear.message, 1, -2);
79                         l -= 2;
80                         if(strstrofs(msg, s, 0) >= 0)
81                                 matchstart = -2; // we use strreplace on s
82                 }
83                 else
84                 {
85                         // match at start
86                         s = substring(ear.message, 1, -1);
87                         l -= 1;
88                         if(substring(msg, -l, l) == s)
89                                 matchstart = strlen(msg) - l;
90                 }
91         }
92         else
93         {
94                 if(substring(ear.message, -1, 1) == "*")
95                 {
96                         // match at end
97                         s = substring(ear.message, 0, -2);
98                         l -= 1;
99                         if(substring(msg, 0, l) == s)
100                                 matchstart = 0;
101                 }
102                 else
103                 {
104                         // full match
105                         s = ear.message;
106                         if(msg == ear.message)
107                                 matchstart = 0;
108                 }
109         }
110
111         if(matchstart == -1) // no match
112                 return msgin;
113
114         magicear_matched = true;
115
116         if(dotrigger)
117         {
118                 savemessage = self.message;
119                 self.message = string_null;
120                 SUB_UseTargets(ear, source, NULL);
121                 self.message = savemessage;
122         }
123
124         if(ear.spawnflags & 16)
125         {
126                 return ear.netname;
127         }
128         else if(ear.netname != "")
129         {
130                 if(matchstart < 0)
131                         return strreplace(s, ear.netname, msg);
132                 else
133                         return strcat(
134                                 substring(msg, 0, matchstart),
135                                 ear.netname,
136                                 substring(msg, matchstart + l, -1)
137                         );
138         }
139         else
140                 return msgin;
141 }
142
143 entity magicears;
144 string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin)
145 {
146         entity ear;
147         string msgout;
148         for(ear = magicears; ear; ear = ear.enemy)
149         {
150                 msgout = trigger_magicear_processmessage(ear, source, teamsay, privatesay, msgin);
151                 if(!(ear.spawnflags & 64))
152                 if(magicear_matched)
153                         return msgout;
154                 msgin = msgout;
155         }
156         return msgin;
157 }
158
159 spawnfunc(trigger_magicear)
160 {
161         self.enemy = magicears;
162         magicears = self;
163
164         // actually handled in "say" processing
165         // spawnflags:
166         //    1 = ignore say
167         //    2 = ignore teamsay
168         //    4 = ignore tell
169         //    8 = ignore tell to unknown player
170         //   16 = let netname replace the whole message (otherwise, netname is a word replacement if set)
171         //   32 = perform the replacement even if outside the radius or dead
172         //   64 = continue replacing/triggering even if this one matched
173         //  128 = don't decolorize message before matching
174         //  256 = message is a tuba note sequence (pitch.duration pitch.duration ...)
175         //  512 = tuba notes must be exact right pitch, no transposing
176         // message: either
177         //   *pattern*
178         // or
179         //   *pattern
180         // or
181         //   pattern*
182         // or
183         //   pattern
184         // netname:
185         //   if set, replacement for the matched text
186         // radius:
187         //   "hearing distance"
188         // target:
189         //   what to trigger
190         // movedir:
191         //   for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter)
192
193         self.movedir_x -= 1; // map to tuba instrument numbers
194 }
195 #endif