666 lines
26 KiB
Plaintext
666 lines
26 KiB
Plaintext
/*======================================================================
|
|
Story books
|
|
======================================================================*/
|
|
// Closed
|
|
$frame closed1 closed2 closed3 closed4 closed5 closed6 closed7 closed8 closed9 closed10
|
|
|
|
// Idle B - looking around turning left and then right (based on closed)
|
|
$frame idleb1 idleb2 idleb3 idleb4 idleb5 idleb6 idleb7 idleb8 idleb9 idleb10
|
|
$frame idleb11 idleb12 idleb13 idleb14 idleb15 idleb16 idleb17 idleb18 idleb19 idleb20
|
|
|
|
// Idle C - spin around 360 degrees (based on closed)
|
|
$frame idlec1 idlec2 idlec3 idlec4 idlec5 idlec6 idlec7 idlec8 idlec9 idlec10
|
|
$frame idlec11 idlec12 idlec13 idlec14 idlec15 idlec16 idlec17 idlec18 idlec19 idlec20
|
|
|
|
// Opening (closed -> open)
|
|
$frame opening1 opening2 opening3 opening4 opening5 opening6 opening7 opening8 opening9 opening10
|
|
|
|
// Open
|
|
$frame open1 open2 open3 open4 open5 open6 open7 open8 open9 open10
|
|
|
|
void() book_closed1;
|
|
void(float fadedir) info_book_fadesetup;
|
|
|
|
//----------------------------------------------------------------------
|
|
float MISCBOOK_NOMODEL = 1; // Will not use any model and particles
|
|
float MISCBOOK_PLINTH1 = 2; // setup and spawn on plinth1
|
|
float MISCBOOK_PLINTH2 = 4; // setup and spawn on plinth2
|
|
float MISCBOOK_STORY = 8; // setup book as part of story
|
|
float MISCBOOK_COLLISION = 16; // Use bounding box collision for plinth
|
|
float MISCBOOK_ANGLEONLY = 32; // Will only work when standing infront of entity
|
|
float MISCBOOK_NOEFFECTS = 128; // Disable particles and effects
|
|
|
|
float MISCBOOK_FADEOUT = 192; // Background density while reading books
|
|
float MISCBOOK_LOOPADVANCE = 0.01;
|
|
|
|
float MISCBOOK_CLOSED = 1;
|
|
float MISCBOOK_OPENING = 2;
|
|
float MISCBOOK_CLOSING = 4;
|
|
float MISCBOOK_OPEN = 8;
|
|
float MISCBOOK_STAYOPEN = 16;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Idle B - looking around turning left and then right (based on closed)
|
|
//----------------------------------------------------------------------
|
|
void() book_idleb1 = [$idleb1, book_idleb2 ] {};
|
|
void() book_idleb2 = [$idleb2, book_idleb3 ] {};
|
|
void() book_idleb3 = [$idleb3, book_idleb4 ] {};
|
|
void() book_idleb4 = [$idleb4, book_idleb5 ] {};
|
|
void() book_idleb5 = [$idleb5, book_idleb6 ] {};
|
|
void() book_idleb6 = [$idleb6, book_idleb7 ] {};
|
|
void() book_idleb7 = [$idleb7, book_idleb8 ] {};
|
|
void() book_idleb8 = [$idleb8, book_idleb9 ] {};
|
|
void() book_idleb9 = [$idleb9, book_idleb10 ] {};
|
|
void() book_idleb10 = [$idleb10, book_idleb11 ] {};
|
|
void() book_idleb11 = [$idleb11, book_idleb12 ] {};
|
|
void() book_idleb12 = [$idleb12, book_idleb13 ] {};
|
|
void() book_idleb13 = [$idleb13, book_idleb14 ] {};
|
|
void() book_idleb14 = [$idleb14, book_idleb15 ] {};
|
|
void() book_idleb15 = [$idleb15, book_idleb16 ] {};
|
|
void() book_idleb16 = [$idleb16, book_idleb17 ] {};
|
|
void() book_idleb17 = [$idleb17, book_idleb18 ] {};
|
|
void() book_idleb18 = [$idleb18, book_idleb19 ] {};
|
|
void() book_idleb19 = [$idleb19, book_idleb20 ] {};
|
|
void() book_idleb20 = [$idleb20, book_closed1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Idle C - spin around 360 degrees (based on closed)
|
|
//----------------------------------------------------------------------
|
|
void() book_idlec1 = [$idlec1, book_idlec2 ] {};
|
|
void() book_idlec2 = [$idlec2, book_idlec3 ] {};
|
|
void() book_idlec3 = [$idlec3, book_idlec4 ] {};
|
|
void() book_idlec4 = [$idlec4, book_idlec5 ] {};
|
|
void() book_idlec5 = [$idlec5, book_idlec6 ] {};
|
|
void() book_idlec6 = [$idlec6, book_idlec7 ] {};
|
|
void() book_idlec7 = [$idlec7, book_idlec8 ] {};
|
|
void() book_idlec8 = [$idlec8, book_idlec9 ] {};
|
|
void() book_idlec9 = [$idlec9, book_idlec10 ] {};
|
|
void() book_idlec10 = [$idlec10, book_idlec11 ] {};
|
|
void() book_idlec11 = [$idlec11, book_idlec12 ] {};
|
|
void() book_idlec12 = [$idlec12, book_idlec13 ] {};
|
|
void() book_idlec13 = [$idlec13, book_idlec14 ] {};
|
|
void() book_idlec14 = [$idlec14, book_idlec15 ] {};
|
|
void() book_idlec15 = [$idlec15, book_idlec16 ] {};
|
|
void() book_idlec16 = [$idlec16, book_idlec17 ] {};
|
|
void() book_idlec17 = [$idlec17, book_idlec18 ] {};
|
|
void() book_idlec18 = [$idlec18, book_idlec19 ] {};
|
|
void() book_idlec19 = [$idlec19, book_idlec20 ] {};
|
|
void() book_idlec20 = [$idlec20, book_closed1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Book closed
|
|
//----------------------------------------------------------------------
|
|
void() book_closed1 = [$closed1, book_closed2 ] {self.state = MISCBOOK_CLOSED;
|
|
if (random() < 0.1 && self.search_time < time) {
|
|
self.search_time = time + 2 + (random()*5);
|
|
self.lefty = 1 - self.lefty;
|
|
if (self.lefty > 0) book_idleb1(); // Turn left and right
|
|
else book_idlec1(); // spin around
|
|
}
|
|
};
|
|
void() book_closed2 = [$closed2, book_closed3 ] {};
|
|
void() book_closed3 = [$closed3, book_closed4 ] {};
|
|
void() book_closed4 = [$closed4, book_closed5 ] {};
|
|
void() book_closed5 = [$closed5, book_closed6 ] {};
|
|
void() book_closed6 = [$closed6, book_closed7 ] {};
|
|
void() book_closed7 = [$closed7, book_closed8 ] {};
|
|
void() book_closed8 = [$closed8, book_closed9 ] {};
|
|
void() book_closed9 = [$closed9, book_closed10 ] {};
|
|
void() book_closed10 = [$closed10, book_closed1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Book closing (open -> close)
|
|
//----------------------------------------------------------------------
|
|
void() book_closing1 = [$opening10, book_closing2 ] {
|
|
self.state = MISCBOOK_CLOSING;
|
|
// make sure book idles don't start straight away
|
|
self.search_time = time + 2 + (random()*5);
|
|
};
|
|
void() book_closing2 = [$opening9, book_closing3 ] {};
|
|
void() book_closing3 = [$opening8, book_closing4 ] {};
|
|
void() book_closing4 = [$opening7, book_closing5 ] {};
|
|
void() book_closing5 = [$opening6, book_closing6 ] {};
|
|
void() book_closing6 = [$opening5, book_closing7 ] {};
|
|
void() book_closing7 = [$opening4, book_closing8 ] {};
|
|
void() book_closing8 = [$opening3, book_closing9 ] {};
|
|
void() book_closing9 = [$opening2, book_closing10 ] {};
|
|
void() book_closing10= [$opening1, book_closed1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Book always open (final stage of book)
|
|
//----------------------------------------------------------------------
|
|
void() book_stayopen1 = [$open1, book_stayopen2 ] {self.state = MISCBOOK_STAYOPEN;};
|
|
void() book_stayopen2 = [$open2, book_stayopen3 ] {};
|
|
void() book_stayopen3 = [$open3, book_stayopen4 ] {};
|
|
void() book_stayopen4 = [$open4, book_stayopen5 ] {};
|
|
void() book_stayopen5 = [$open5, book_stayopen6 ] {};
|
|
void() book_stayopen6 = [$open6, book_stayopen7 ] {};
|
|
void() book_stayopen7 = [$open7, book_stayopen8 ] {};
|
|
void() book_stayopen8 = [$open8, book_stayopen9 ] {};
|
|
void() book_stayopen9 = [$open9, book_stayopen10 ] {};
|
|
void() book_stayopen10 = [$open10, book_stayopen1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Players has walked away, decide what to do with the book
|
|
//----------------------------------------------------------------------
|
|
void() book_finish =
|
|
{
|
|
info_book_fadesetup(-1);
|
|
// Clear client centerprint suppression
|
|
if (self.enemy.flags & FL_CLIENT) {
|
|
self.enemy.suppressCenterPrint = FALSE;
|
|
centerprint(self.enemy, "");
|
|
}
|
|
if (self.pain_finished > 0) book_stayopen1();
|
|
else book_closing1();
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Book is open (waiting to close)
|
|
//----------------------------------------------------------------------
|
|
void() book_open1 = [$open1, book_open2 ] {self.state = MISCBOOK_OPEN;};
|
|
void() book_open2 = [$open2, book_open3 ] {if (self.wait < time) book_finish();};
|
|
void() book_open3 = [$open3, book_open4 ] {};
|
|
void() book_open4 = [$open4, book_open5 ] {if (self.wait < time) book_finish();};
|
|
void() book_open5 = [$open5, book_open6 ] {};
|
|
void() book_open6 = [$open6, book_open7 ] {if (self.wait < time) book_finish();};
|
|
void() book_open7 = [$open7, book_open8 ] {};
|
|
void() book_open8 = [$open8, book_open9 ] {if (self.wait < time) book_finish();};
|
|
void() book_open9 = [$open9, book_open10 ] {};
|
|
void() book_open10= [$open10, book_open1 ] {if (self.wait < time) book_finish();};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Book opening (closed -> open)
|
|
//----------------------------------------------------------------------
|
|
void() book_opening1 = [$opening1, book_opening2 ] {self.state = MISCBOOK_OPENING;};
|
|
void() book_opening2 = [$opening2, book_opening3 ] {};
|
|
void() book_opening3 = [$opening3, book_opening4 ] {};
|
|
void() book_opening4 = [$opening4, book_opening5 ] {};
|
|
void() book_opening5 = [$opening5, book_opening6 ] {};
|
|
void() book_opening6 = [$opening6, book_opening7 ] {};
|
|
void() book_opening7 = [$opening7, book_opening8 ] {};
|
|
void() book_opening8 = [$opening8, book_opening9 ] {};
|
|
void() book_opening9 = [$opening9, book_opening10 ] {};
|
|
void() book_opening10 = [$opening10, book_open1 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() info_book_fade =
|
|
{
|
|
if (self.estate & ESTATE_BLOCK) return;
|
|
|
|
// Fade direction needs to be -1 or +1 (0.48s fade time)
|
|
self.lip = self.lip + (self.height * 4);
|
|
// Check if fade has reached 0 or max screen fade value
|
|
if (self.lip <= 0) self.lip = 0;
|
|
else if (self.lip >= MISCBOOK_FADEOUT) self.lip = MISCBOOK_FADEOUT;
|
|
else self.nextthink = time + MISCBOOK_LOOPADVANCE;
|
|
|
|
// Only update the screen if the debuff system is NOT active
|
|
// and the client does NOT have any powerups active
|
|
if (!self.enemy.cshift_upd && self.enemy.items & ALL_ITARTIFACTS == 0) {
|
|
// Change screen background density (makes text easier to read)
|
|
stuffcmd(self.enemy, "v_cshift 0 0 0 ");
|
|
stuffcmd(self.enemy, ftos(self.lip));
|
|
stuffcmd(self.enemy, "\n");
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void(float fadedir) info_book_fadesetup =
|
|
{
|
|
if (self.estate & ESTATE_BLOCK) return;
|
|
|
|
// Is the fade controller setup?
|
|
if (self.attachment) {
|
|
// Double check if screen fade is setup already
|
|
if (fadedir > 0 && self.attachment.lip == MISCBOOK_FADEOUT) return;
|
|
if (fadedir < 0 && self.attachment.lip == 0) return;
|
|
|
|
// Copy over client and fadedir to controller
|
|
self.attachment.enemy = self.enemy;
|
|
self.attachment.height = fadedir;
|
|
self.attachment.think = info_book_fade;
|
|
self.attachment.nextthink = time + MISCBOOK_LOOPADVANCE;
|
|
self.attachment.ltime = self.attachment.nextthink;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() info_book_displaystory =
|
|
{
|
|
// is this book part of a storyline?
|
|
// The controller has been setup/validated already
|
|
if (self.spawnflags & MISCBOOK_STORY) {
|
|
// Check controller once!
|
|
self.spawnflags = self.spawnflags - (self.spawnflags & MISCBOOK_STORY);
|
|
|
|
if (self.attachment.estate == ESTATE_OFF) {
|
|
self.message = "Story controller broken!\n\n";
|
|
}
|
|
else {
|
|
// Copy over story chapter
|
|
self.message = self.attachment.oldenemy.message;
|
|
self.message2 = self.attachment.oldenemy.message2;
|
|
self.message3 = self.attachment.oldenemy.message3;
|
|
self.message4 = self.attachment.oldenemy.message4;
|
|
}
|
|
|
|
// Work out which centerprint to use
|
|
if (self.message3 != "" && self.message4 != "") self.cnt = 2;
|
|
else if (self.message3 != "") self.cnt = 1;
|
|
else self.cnt = 0;
|
|
|
|
// Move controller on to next story chapter
|
|
if (self.attachment.height < self.attachment.count) {
|
|
self.attachment.count = self.attachment.count + 1;
|
|
self.attachment.oldenemy = self.attachment.oldenemy.oldenemy;
|
|
}
|
|
}
|
|
|
|
// Suppress any other centerprint messages and show story
|
|
self.enemy.suppressCenterPrint = TRUE;
|
|
// Check for any additional strings and use correct centerprint
|
|
// The engine function will merge several strings together
|
|
if (self.cnt == 1) centerprint_msg3(self.enemy, self.message, self.message2, self.message3);
|
|
else if (self.cnt == 2) centerprint_msg4(self.enemy, self.message, self.message2, self.message3, self.message4);
|
|
else centerprint_msg(self.enemy, self.message, self.message2);
|
|
|
|
// Check for any additional trigger events
|
|
if (self.target != "") {
|
|
trigger_strs(self.target, self.enemy);
|
|
self.target = "";
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() info_book_touch =
|
|
{
|
|
local float book_yaw, book_angle1, book_angle2, play_yaw, play_angle;
|
|
|
|
if (self.estate & ESTATE_BLOCK) return;
|
|
if (intermission_running) return; // intermission or finale
|
|
if ( !(other.flags & FL_CLIENT) ) return;
|
|
if (other.health < 1) return;
|
|
|
|
// Store player entity for later use
|
|
self.enemy = other;
|
|
|
|
if (self.spawnflags & MISCBOOK_ANGLEONLY) {
|
|
// Check the players facing direction against book angle direction
|
|
// make sure the player angle is never negative, + 360 just in case
|
|
play_angle = anglemod(self.enemy.v_angle_y+360);
|
|
// Work out angle cone based on book angle direction
|
|
// Use previously defined angles for viewing angle of book
|
|
book_yaw = fabs(self.v_angle_y - self.v_angle_x);
|
|
book_angle1 = anglemod(self.angles_y + 180 + (360-book_yaw));
|
|
book_angle2 = anglemod(self.angles_y + 180 + book_yaw);
|
|
// Is the players angle outside the book's viewing range?
|
|
if (play_angle < book_angle1 || play_angle > book_angle2) return;
|
|
}
|
|
|
|
// The angle at the which the book is facing the player
|
|
// book_yaw = vectoyaw(self.enemy.origin - self.origin);
|
|
// book_angle = anglemod((self.angles_y - book_yaw) + 0);
|
|
// The angle the player is facing towards the book (45 = forward)
|
|
play_yaw = vectoyaw(self.origin - self.enemy.origin);
|
|
play_angle = anglemod((self.enemy.v_angle_y - play_yaw) + 45);
|
|
|
|
// Is the player looking at the book?
|
|
if (play_angle > self.v_angle_x && play_angle < self.v_angle_y) {
|
|
// Is the book closed?
|
|
if (self.state == MISCBOOK_CLOSED) {
|
|
self.wait = time + 1.3;
|
|
book_opening1();
|
|
}
|
|
// Is the book currently open and been read before?
|
|
else if (self.state == MISCBOOK_STAYOPEN) {
|
|
info_book_fadesetup(1);
|
|
self.wait = time + 0.3;
|
|
self.attack_finished = time + 0.2;
|
|
book_open1();
|
|
}
|
|
// Has the book just opened and never been read before?
|
|
else if (self.state == MISCBOOK_OPEN && self.pain_finished == FALSE) {
|
|
self.pain_finished = TRUE;
|
|
info_book_fadesetup(1);
|
|
self.wait = time + 0.3;
|
|
self.attack_finished = time + 0.2;
|
|
if (self.part_emitter) misc_particle_update(self.part_emitter, PARTICLE_STYLE_OPENBOOK);
|
|
info_book_displaystory();
|
|
}
|
|
// Is the book open and ready for a story?
|
|
else if (self.state == MISCBOOK_OPEN) {
|
|
info_book_fadesetup(1);
|
|
self.wait = time + 0.3;
|
|
if (self.attack_finished < time) {
|
|
self.attack_finished = time + 0.2;
|
|
info_book_displaystory();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() info_book_on =
|
|
{
|
|
self.estate = ESTATE_ON;
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.solid = SOLID_TRIGGER;
|
|
if ( !(self.spawnflags & MISCBOOK_NOMODEL) ) {
|
|
setmodel (self, self.mdl);
|
|
self.skin = self.exactskin;
|
|
}
|
|
|
|
// Make sure particle emitter is turned on
|
|
if (self.part_emitter) misc_particle_on(self.part_emitter);
|
|
|
|
// Setup touch trigger and function
|
|
self.touch = info_book_touch;
|
|
setsize (self, self.pos1, self.pos2);
|
|
|
|
// If no model, don't need book animations + attachment models
|
|
if ( !(self.spawnflags & MISCBOOK_NOMODEL) ) {
|
|
// Check for any plinth models
|
|
if (self.attachment2) {
|
|
// Use bounding box coillsion?
|
|
if (self.spawnflags & MISCBOOK_COLLISION) self.attachment2.solid = SOLID_BBOX;
|
|
else self.attachment2.solid = SOLID_NOT;
|
|
setmodel (self.attachment2, self.noise1);
|
|
}
|
|
|
|
// Setup book in correct animation state
|
|
self.search_time = time + 5 + (random()*5); // delay idle animation
|
|
if (self.state == MISCBOOK_CLOSED) book_closed1();
|
|
else book_stayopen1();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() info_book_off =
|
|
{
|
|
self.estate = ESTATE_OFF;
|
|
self.solid = SOLID_NOT;
|
|
setmodel (self, "");
|
|
|
|
// Stop any touch/animations
|
|
self.touch = self.think = SUB_Null;
|
|
|
|
// Check if the screen is faded?
|
|
if (self.attachment) {
|
|
if (self.attachment.lip != 0) {
|
|
self.attachment.lip = 0;
|
|
if (!self.enemy.cshift_upd && self.enemy.items & ALL_ITARTIFACTS == 0) {
|
|
stuffcmd(self.enemy, "v_cshift 0 0 0 0\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// If any plinth exists, turn that off as well
|
|
if (self.attachment2) {
|
|
setmodel(self.attachment2, "");
|
|
self.attachment2.solid = SOLID_NOT;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() info_book_setup =
|
|
{
|
|
// Setup book fade controller
|
|
self.attachment = spawn();
|
|
self.attachment.owner = self;
|
|
self.attachment.classtype = CT_CONTROL;
|
|
self.attachment.movetype = MOVETYPE_NONE;
|
|
setorigin(self.attachment,self.origin + '0 0 32');
|
|
setsize (self.attachment, VEC_ORIGIN, VEC_ORIGIN);
|
|
|
|
// Check for plinth and spawn/setup
|
|
if (self.mdl != "" && self.noise1 != "") {
|
|
self.attachment2 = spawn();
|
|
self.attachment2.owner = self;
|
|
self.attachment2.classtype = CT_MISCMODEL;
|
|
self.attachment2.movetype = MOVETYPE_NONE;
|
|
|
|
// Trace downward to find the ground and place plinth
|
|
traceline (self.origin, self.origin + '0 0 -512', TRUE, self);
|
|
self.origin = trace_endpos + '0 0 32';
|
|
setorigin(self.attachment2, self.origin);
|
|
self.attachment2.angles = self.angles;
|
|
|
|
// Plinth2 has flat surface which conflicts with book angle
|
|
if (self.spawnflags & MISCBOOK_PLINTH2) self.origin = self.origin + '0 0 4';
|
|
}
|
|
|
|
// Check for random skin options
|
|
if (self.randomskin > 1)
|
|
self.exactskin = rint(random()*(self.randomskin-1));
|
|
// The particle colours are based on the book skin
|
|
if (self.exactskin < 1) self.exactskin = 0;
|
|
if (self.exactskin >= 6) self.style = MISCBOOK_RED;
|
|
else if (self.exactskin >= 4) self.style = MISCBOOK_BLUE;
|
|
else self.style = MISCBOOK_GREEN;
|
|
|
|
// Default viewing angle is min 30 and max 60 looking at origin
|
|
if (CheckZeroVector(self.v_angle)) self.v_angle = '30 60 0';
|
|
if (self.angles_y == 0) self.angles_y = 360;
|
|
|
|
// Check for story book setup first
|
|
// Story is supplied from story system when book is opened
|
|
if (self.spawnflags & MISCBOOK_STORY) {
|
|
// Reset all storybook message strings
|
|
self.message = "Waiting for story!";
|
|
self.message2 = "";
|
|
self.message3 = ""; self.message4 = "";
|
|
self.cnt = 0;
|
|
self.attachment = find(world, targetname, self.target2);
|
|
// Is this entity a storybook controller?
|
|
if (!self.attachment || self.attachment.classtype != CT_STORYCONTROL)
|
|
{
|
|
dprint("\b[STORYBOOK]\b Missing controller!\n");
|
|
spawn_marker(self.origin, SPNMARK_YELLOW);
|
|
entity_hide(self);
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
// setup default message for testing
|
|
if (self.message == "") self.message = "\b--[ Dark Elder Magic ]--\b\n\n";
|
|
if (self.message2 == "") self.message2 = "Despite the awful might of the Elder\nWorld, you have achieved the Rune of\nElder Magic, capstone of all types of\narcane wisdom. Beyond good and evil,\nbeyond life and death, the Rune\npulsates, heavy with import.\n";
|
|
|
|
// Check for additional strings to display
|
|
// This is to fix quark editor limit of 128 characters per string
|
|
if (self.message3 != "" && self.message4 != "") self.cnt = 2;
|
|
else if (self.message3 != "") self.cnt = 1;
|
|
else self.cnt = 0;
|
|
}
|
|
|
|
// Spawn particle emitter if particles active and not blocked
|
|
if ( !(self.spawnflags & MISCBOOK_NOMODEL) ) {
|
|
self.part_active = PARTICLE_STYLE_BOOK;
|
|
if (self.spawnflags & ENT_STARTOFF) self.count = PARTICLE_START_OFF;
|
|
else self.count = PARTICLE_START_ON;
|
|
if (query_configflag(SVR_PARTICLES) == SVR_PARTICLES) {
|
|
if (!(self.spawnflags & MISCBOOK_NOEFFECTS) && self.part_active > 0)
|
|
self.part_emitter = spawn_pemitter(self, self, self.part_active, self.count);
|
|
}
|
|
}
|
|
|
|
// Setup Entity State functionality
|
|
if (self.targetname != "") self.use = entity_state_use;
|
|
self.estate_on = info_book_on;
|
|
self.estate_off = info_book_off;
|
|
if (self.spawnflags & ENT_STARTOFF) self.estate_off();
|
|
else self.estate_on();
|
|
};
|
|
|
|
/*======================================================================
|
|
/*QUAKED misc_textbook (0 0.5 0.5) (-16 -16 -8) (16 16 8) NOMODEL PLINTH1 PLINTH2 STORY COLLISION ANGLEONLY STARTOFF NOEFFECTS
|
|
Display custom text messages
|
|
-------- KEYS --------
|
|
targetname : toggle state (use trigger ent for exact state)
|
|
target : trigger event when book is opened (only works once)
|
|
target2 : name of story controller (only works with spawnflag)
|
|
angle : facing angle for model or direction player must be standing
|
|
v_angle : The viewing angle the book is active (def=30,60,0)
|
|
exactskin : skin number for book (1-8, Brown1/2,Green1/2,Blue1/2,Red1/2)
|
|
pos1 : Touch trigger minimin size (def=-48 -48 -32)
|
|
pos2 : Touch trigger maximum size (def=48 48 32)
|
|
message : header message
|
|
message2 : Body Text 1 (need to add linefeeds)
|
|
message3 : Body Text 2 (displayed after message2)
|
|
message4 : Body Text 3 (displayed after message3)
|
|
-------- SPAWNFLAGS --------
|
|
NOMODEL : Will not use book model + particles
|
|
PLINTH1 : Setup book on top of plinth1 model
|
|
PLINTH2 : Setup book on top of plinth2 model
|
|
STORY : Book is part of a story (use target2)
|
|
COLLISION : Use bounding box collision for plinth
|
|
ANGLEONLY : Will only work when standing infront of entity (angle key)
|
|
STARTOFF : Starts off and waits for trigger
|
|
NOEFFECTS : No particle or effects active
|
|
-------- NOTES --------
|
|
Display custom text messages
|
|
Maximum size of message is 1024 characters, 256 is the original limit
|
|
|
|
======================================================================*/
|
|
void() misc_textbook =
|
|
{
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.solid = SOLID_NOT;
|
|
self.classtype = CT_STORYBOOK;
|
|
|
|
// Setup large bounding box for touch trigger
|
|
if (CheckZeroVector(self.pos1)) self.pos1 = '-48 -48 -32';
|
|
if (CheckZeroVector(self.pos2)) self.pos2 = '48 48 32';
|
|
self.takedamage = DAMAGE_NO; // No damage from anything
|
|
|
|
if (self.spawnflags & MISCBOOK_NOMODEL) {
|
|
self.mdl = "";
|
|
self.state = MISCBOOK_STAYOPEN; // no book animation
|
|
self.pain_finished = TRUE; // No read delay
|
|
}
|
|
else {
|
|
self.state = MISCBOOK_CLOSED; // Current state
|
|
self.pain_finished = FALSE; // Book not read yet
|
|
// Default medieval book
|
|
self.mdl = "progs/misc_textbook.mdl";
|
|
precache_model (self.mdl);
|
|
self.noise1 = "";
|
|
// Check for any predefined plinth model setups
|
|
if (self.spawnflags & MISCBOOK_PLINTH1) {
|
|
self.noise1 = "progs/misc_plinth1.mdl";
|
|
precache_model(self.noise1);
|
|
}
|
|
else if (self.spawnflags & MISCBOOK_PLINTH2) {
|
|
self.noise1 = "progs/misc_plinth2.mdl";
|
|
precache_model(self.noise1);
|
|
}
|
|
}
|
|
|
|
// Don't spawn straight away
|
|
self.nextthink = time + 0.1 + random()*0.4;
|
|
self.think = info_book_setup;
|
|
};
|
|
|
|
/*======================================================================
|
|
/*QUAKED misc_textstory (0 0.5 1.0) (-16 -16 -8) (16 16 8) x
|
|
Text Book Story Chapters
|
|
-------- KEYS --------
|
|
targetname : name of current chapter
|
|
target : name of next chapter
|
|
message : header message
|
|
message2 : Body Text 1 (need to add linefeeds)
|
|
message3 : Body Text 2 (displayed after message2)
|
|
message4 : Body Text 3 (displayed after message3)
|
|
-------- SPAWNFLAGS --------
|
|
-------- NOTES --------
|
|
Text Book Story Chapters
|
|
|
|
/*QUAKED misc_textstoryctrl (0 0.1 1.0) (-16 -16 -8) (16 16 8) x
|
|
Text Book Story Controller
|
|
-------- KEYS --------
|
|
targetname : name of controller for story
|
|
target : name of first chapter
|
|
-------- SPAWNFLAGS --------
|
|
-------- NOTES --------
|
|
Text Book Story Controller
|
|
|
|
======================================================================*/
|
|
void() info_bookcont_setup =
|
|
{
|
|
local entity storychap, prevchap;
|
|
|
|
// Is there any story chapters?
|
|
storychap = find(world, targetname, self.target);
|
|
if (!storychap) {
|
|
dprint("\b[STORYCTRL]\b Missing start chapter!\n");
|
|
spawn_marker(self.origin, SPNMARK_YELLOW);
|
|
return;
|
|
}
|
|
|
|
// Can only link to story chapter entities
|
|
if (storychap.classtype != CT_STORYCHAPTER) {
|
|
dprint("\b[STORYCTRL]\b First chapter wrong entity!\n");
|
|
spawn_marker(self.origin, SPNMARK_YELLOW);
|
|
return;
|
|
}
|
|
|
|
// Setup controller
|
|
prevchap = self; // Start controller at chapter 1
|
|
self.count = 0; // Total chapters in story
|
|
self.height = 1; // Current chapter in story
|
|
|
|
// Work through list
|
|
while (storychap) {
|
|
// Visual debug for chapters
|
|
spawn_marker(storychap.origin, SPNMARK_BLUE);
|
|
|
|
// Link chapters and move forward
|
|
prevchap.oldenemy = storychap;
|
|
prevchap = storychap;
|
|
self.count = self.count + 1;
|
|
|
|
// Check for next target in chain
|
|
if (prevchap.target == "") storychap = world;
|
|
else storychap = find(world, targetname, prevchap.target);
|
|
}
|
|
// Point final chapter at itself
|
|
prevchap.oldenemy = prevchap;
|
|
|
|
// Controller finally active
|
|
self.estate = ESTATE_ON;
|
|
// Visual debug for controller
|
|
spawn_marker(self.origin, SPNMARK_GREEN);
|
|
// Console message for chapters found
|
|
dprint("\b[STORYCTRL]\b Chapters found (");
|
|
dprint(ftos(self.count));
|
|
dprint(")\n");
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() misc_textstoryctrl =
|
|
{
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.solid = SOLID_NOT;
|
|
self.classtype = CT_STORYCONTROL;
|
|
// Start in disabled state until chapters setup
|
|
self.estate = ESTATE_OFF;
|
|
|
|
if (self.target == "") {
|
|
dprint("\b[STORYCTRL]\b Missing story start!\n");
|
|
spawn_marker(self.origin, SPNMARK_YELLOW);
|
|
return;
|
|
}
|
|
|
|
// Wait for chapter and books to spawn first
|
|
self.nextthink = time + 1 + random();
|
|
self.think = info_bookcont_setup;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() misc_textstory =
|
|
{
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.solid = SOLID_NOT;
|
|
self.classtype = CT_STORYCHAPTER;
|
|
};
|