Files
quakemapping/mod_ad_dev/my_progs/misc_textbook.qc
2019-12-30 22:24:44 +01:00

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;
};