3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
17 # include <SDL_mixer.h>
32 felist
msgsystem::MessageHistory(CONST_S("Message history"), WHITE
, 128);
33 festring
msgsystem::LastMessage
;
34 festring
msgsystem::BigMessage
;
36 v2
msgsystem::Begin
, msgsystem::End
;
37 truth
msgsystem::Enabled
= true;
38 truth
msgsystem::BigMessageMode
= false;
39 truth
msgsystem::MessagesChanged
= true;
40 bitmap
* msgsystem::QuickDrawCache
= 0;
41 int msgsystem::LastMessageLines
;
44 void msgsystem::AddMessage (cchar
*Format
, ...) {
46 if (BigMessageMode
&& BigMessage
.GetSize() >= 512) LeaveBigMessageMode();
51 vsnprintf(Message
, sizeof(Message
)-1, Format
, AP
);
54 festring
Buffer(Message
);
56 if (!Buffer
.GetSize()) ABORT("Empty message request!");
58 soundsystem::playSound(Buffer
);
62 /* Comment the first line and uncomment the second before the release! */
63 if (isalpha(Buffer
[Buffer
.GetSize()-1]))
64 //Buffer << " (this sentence isn't terminated correctly because Hex doesn't know grammar rules)";
68 if (BigMessage
.GetSize()) BigMessage
<< ' ';
76 if (Buffer
== LastMessage
) {
77 for (int c
= 0; c
< LastMessageLines
; ++c
) MessageHistory
.Pop();
79 End
= v2(Time
.Hour
, Time
.Min
);
82 Begin
= End
= v2(Time
.Hour
, Time
.Min
);
84 LastMessage
.ensureUniqueOwned();
88 Temp
<< Begin
.X
<< ':';
97 Temp
<< '-' << End
.X
<< ':';
106 Temp
<< " (" << Times
<< "x)";
109 int Marginal
= Temp
.GetSize();
112 std::vector
<festring
> Chapter
;
113 festring::SplitString(Temp
, Chapter
, 78, Marginal
);
115 for(uInt c
= 0; c
< Chapter
.size(); ++c
)
116 MessageHistory
.AddEntry(Chapter
[c
], WHITE
);
118 MessageHistory
.SetSelected(MessageHistory
.GetLastEntryIndex());
119 LastMessageLines
= Chapter
.size();
120 MessagesChanged
= true;
123 void msgsystem::Draw()
125 truth WasInBigMessageMode
= BigMessageMode
;
126 LeaveBigMessageMode();
130 MessageHistory
.QuickDraw(QuickDrawCache
, 8);
131 MessagesChanged
= false;
134 v2 Size
= QuickDrawCache
->GetSize();
136 blitdata B
= { DOUBLE_BUFFER
,
144 QuickDrawCache
->NormalBlit(B
);
145 igraph::BlitBackGround(v2(13, Y
), v2(1, 1));
146 igraph::BlitBackGround(v2(12 + Size
.X
, Y
), v2(1, 1));
147 igraph::BlitBackGround(v2(13, Y
+ Size
.Y
- 1), v2(1, 1));
148 igraph::BlitBackGround(v2(12 + Size
.X
, Y
+ Size
.Y
- 1), v2(1, 1));
150 if(WasInBigMessageMode
)
151 EnterBigMessageMode();
154 void msgsystem::DrawMessageHistory()
156 MessageHistory
.Draw();
159 void msgsystem::Format()
161 MessageHistory
.Empty();
163 MessagesChanged
= true;
164 BigMessageMode
= false;
167 void msgsystem::Save(outputfile
& SaveFile
)
169 MessageHistory
.Save(SaveFile
);
170 SaveFile
<< LastMessage
<< Times
<< Begin
<< End
;
173 void msgsystem::Load(inputfile
& SaveFile
)
175 MessageHistory
.Load(SaveFile
);
176 SaveFile
>> LastMessage
>> Times
>> Begin
>> End
;
179 void msgsystem::ScrollDown()
181 if(MessageHistory
.GetSelected() < MessageHistory
.GetLastEntryIndex())
183 MessageHistory
.EditSelected(1);
184 MessagesChanged
= true;
188 void msgsystem::ScrollUp()
190 if(MessageHistory
.GetSelected())
192 MessageHistory
.EditSelected(-1);
193 MessagesChanged
= true;
197 void msgsystem::LeaveBigMessageMode()
199 BigMessageMode
= false;
201 if(BigMessage
.GetSize())
203 AddMessage("%s", BigMessage
.CStr());
208 void msgsystem::Init()
210 QuickDrawCache
= new bitmap(v2((game::GetScreenXSize() << 4) + 6, 106));
211 QuickDrawCache
->ActivateFastFlag();
212 game::SetStandardListAttributes(MessageHistory
);
213 MessageHistory
.AddFlags(INVERSE_MODE
);
216 void msgsystem::ThyMessagesAreNowOld()
218 if(MessageHistory
.GetColor(MessageHistory
.GetLastEntryIndex()) == WHITE
)
219 MessagesChanged
= true;
221 for(uInt c
= 0; c
< MessageHistory
.GetLength(); ++c
)
222 MessageHistory
.SetColor(c
, LIGHT_GRAY
);
227 #ifndef DISABLE_SOUND
229 #define SND_CHANNEL_COUNT (16)
242 std::vector
<int> sounds
;
245 int soundsystem::SoundState
= 0;
247 std::vector
<SoundFile
> soundsystem::files
;
248 std::vector
<SoundInfo
> soundsystem::patterns
;
251 int soundsystem::addFile (const festring
&filename
) {
252 for (int i
= 0; i
< int(files
.size()); i
++) if (files
[i
].filename
== filename
) return i
;
254 p
.filename
= filename
;
258 return files
.size()-1;
263 static festring
getstr (FILE *f
, truth word
) {
264 if (eol
&& word
) return "";
268 if (c
== EOF
) return s
;
269 if (c
== 13) continue;
270 if (c
== 10 && s
!= "") return eol
= true, s
;
271 if (c
== 10) continue;
272 if (c
== ' ' && word
&& s
!= "") return s
;
278 void soundsystem::initSound () {
281 if (SoundState
== 0) {
282 //FILE *debf = fopen("snddebug.txt", "wt");
284 if (debf
) fprintf(debf
, "This file can be used to diagnose problems with sound.\n");
285 if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT
, 2, 8000) != 0) {
286 ADD_MESSAGE("Unable to initialize audio: %s", Mix_GetError());
287 if (debf
) fprintf(debf
, "Unable to initialize audio: %s\n", Mix_GetError());
291 Mix_AllocateChannels(SND_CHANNEL_COUNT
);
292 setVolume(ivanconfig::GetSoundVolume());
294 festring cfgfile
= game::GetGameDir()+"sound/config.txt";
295 FILE *f
= fopen(cfgfile
.CStr(), "r");
296 if (!f
) SoundState
= -1;
298 festring Pattern
, File
;
299 while ((Pattern
= getstr(f
, false)) != "") {
302 si.re = pcre_compile(Pattern.CStr(), 0, &error, &erroffset, NULL);
304 if (debf) fprintf(debf, "PCRE compilation failed at expression offset %d: %s\n", erroffset, error);
305 ADD_MESSAGE("PCRE compilation failed at expression offset %d: %s", erroffset, error);
307 si.extra = pcre_study(si.re, 0, &error);
310 si
.re
= SEE_regex_parse(Pattern
.CStr(), Pattern
.GetSize(), SEERX_FLAG_IGNORECASE
);
312 ADD_MESSAGE("Sound RegExpr compilation failed: %s", Pattern
.CStr());
315 while ((File
= getstr(f
, true)) != "") si
.sounds
.push_back(addFile(File
));
316 if (si
.sounds
.size() != 0) patterns
.push_back(si
);
320 //Mix_HookMusicFinished(changeMusic);
322 if (debf
) fclose(debf
);
327 SoundFile
*soundsystem::findMatchingSound (const festring
&Buffer
) {
328 for (int f
= patterns
.size()-1; f
>= 0; --f
) {
329 if (patterns
[f
].re
) {
331 if (pcre_exec(patterns[f].re, patterns[f].extra, Buffer.CStr(), Buffer.GetSize(), 0, 0, NULL, 0) >= 0) {
332 return &files[patterns[f].sounds[rand()%patterns[f].sounds.size()]];
335 if (SEE_regex_match(patterns
[f
].re
, Buffer
.CStr(), Buffer
.GetSize(), 0, NULL
)) {
336 return &files
[patterns
[f
].sounds
[rand()%patterns
[f
].sounds
.size()]];
344 void soundsystem::setVolume (sLong vol
) {
345 if (vol
< 0) vol
= 0; else if (vol
> 128) vol
= 128;
346 if (SoundState
== 1) {
347 for (int f
= 0; f
< SND_CHANNEL_COUNT
; f
++) Mix_Volume(f
, vol
);
352 void soundsystem::playSound (const festring
&Buffer
) {
353 if (!ivanconfig::GetPlaySounds()) return;
355 if (SoundState
== 1) {
356 SoundFile
*sf
= findMatchingSound(Buffer
);
359 festring sndfile
= game::GetGameDir()+"sound/"+sf
->filename
;
360 //fprintf(stderr, "loading sound: '%s'\n", sndfile.CStr());
361 sf
->chunk
= Mix_LoadWAV(sndfile
.CStr());
364 for (int f
= 0; f
< SND_CHANNEL_COUNT
; ++f
) {
365 if (!Mix_Playing(f
)) {
366 //fprintf(stderr, "starting sound: '%s'\n", sf->filename.CStr());
367 Mix_Volume(f
, ivanconfig::GetSoundVolume());
368 Mix_PlayChannel(f
, sf
->chunk
, 0);
369 //Mix_SetPosition(f, angle, dist);
379 void soundsystem::initSound () {}
380 int soundsystem::addFile (const festring
&filename
) { return 0; }
381 SoundFile
*soundsystem::findMatchingSound (const festring
&Buffer
) { return NULL
; }
382 void soundsystem::playSound (const festring
&Buffer
) {}
383 void soundsystem::setVolume (sLong vol
) {}