g_newfnc.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "g_local.h"
  4. //void plat_CalcMove (edict_t *ent, vec3_t dest, void(*func)(edict_t*));
  5. void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*));
  6. void fd_secret_move1(edict_t *self);
  7. void fd_secret_move2(edict_t *self);
  8. void fd_secret_move3(edict_t *self);
  9. void fd_secret_move4(edict_t *self);
  10. void fd_secret_move5(edict_t *self);
  11. void fd_secret_move6(edict_t *self);
  12. void fd_secret_done(edict_t *self);
  13. /*
  14. =============================================================================
  15. SECRET DOORS
  16. =============================================================================
  17. */
  18. #define SEC_OPEN_ONCE 1 // stays open
  19. #define SEC_1ST_LEFT 2 // 1st move is left of arrow
  20. #define SEC_1ST_DOWN 4 // 1st move is down from arrow
  21. #define SEC_NO_SHOOT 8 // only opened by trigger
  22. #define SEC_YES_SHOOT 16 // shootable even if targeted
  23. #define SEC_MOVE_RIGHT 32
  24. #define SEC_MOVE_FORWARD 64
  25. void fd_secret_use (edict_t *self, edict_t *other, edict_t *activator)
  26. {
  27. edict_t *ent;
  28. // gi.dprintf("fd_secret_use\n");
  29. if (self->flags & FL_TEAMSLAVE)
  30. return;
  31. // trigger all paired doors
  32. for (ent = self ; ent ; ent = ent->teamchain)
  33. Move_Calc(ent, ent->moveinfo.start_origin, fd_secret_move1);
  34. }
  35. void fd_secret_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  36. {
  37. // gi.dprintf("fd_secret_killed\n");
  38. self->health = self->max_health;
  39. self->takedamage = DAMAGE_NO;
  40. if (self->flags & FL_TEAMSLAVE && self->teammaster && self->teammaster->takedamage != DAMAGE_NO)
  41. fd_secret_killed (self->teammaster, inflictor, attacker, damage, point);
  42. else
  43. fd_secret_use (self, inflictor, attacker);
  44. }
  45. // Wait after first movement...
  46. void fd_secret_move1(edict_t *self)
  47. {
  48. // gi.dprintf("fd_secret_move1\n");
  49. self->nextthink = level.time + 1.0;
  50. self->think = fd_secret_move2;
  51. }
  52. // Start moving sideways w/sound...
  53. void fd_secret_move2(edict_t *self)
  54. {
  55. // gi.dprintf("fd_secret_move2\n");
  56. Move_Calc(self, self->moveinfo.end_origin, fd_secret_move3);
  57. }
  58. // Wait here until time to go back...
  59. void fd_secret_move3(edict_t *self)
  60. {
  61. // gi.dprintf("fd_secret_move3\n");
  62. if (!(self->spawnflags & SEC_OPEN_ONCE))
  63. {
  64. self->nextthink = level.time + self->wait;
  65. self->think = fd_secret_move4;
  66. }
  67. }
  68. // Move backward...
  69. void fd_secret_move4(edict_t *self)
  70. {
  71. // gi.dprintf("fd_secret_move4\n");
  72. Move_Calc(self, self->moveinfo.start_origin, fd_secret_move5);
  73. }
  74. // Wait 1 second...
  75. void fd_secret_move5(edict_t *self)
  76. {
  77. // gi.dprintf("fd_secret_move5\n");
  78. self->nextthink = level.time + 1.0;
  79. self->think = fd_secret_move6;
  80. }
  81. void fd_secret_move6(edict_t *self)
  82. {
  83. // gi.dprintf("fd_secret_move6\n");
  84. Move_Calc(self, self->move_origin, fd_secret_done);
  85. }
  86. void fd_secret_done(edict_t *self)
  87. {
  88. // gi.dprintf("fd_secret_done\n");
  89. if (!self->targetname || self->spawnflags & SEC_YES_SHOOT)
  90. {
  91. self->health = 1;
  92. self->takedamage = DAMAGE_YES;
  93. self->die = fd_secret_killed;
  94. }
  95. }
  96. void secret_blocked(edict_t *self, edict_t *other)
  97. {
  98. if (!(self->flags & FL_TEAMSLAVE))
  99. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 0, 0, MOD_CRUSH);
  100. // if (time < self->attack_finished)
  101. // return;
  102. // self->attack_finished = time + 0.5;
  103. // T_Damage (other, self, self, self->dmg);
  104. }
  105. /*
  106. ================
  107. secret_touch
  108. Prints messages
  109. ================
  110. */
  111. void secret_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  112. {
  113. if (other->health <= 0)
  114. return;
  115. if (!(other->client))
  116. return;
  117. if (self->monsterinfo.attack_finished > level.time)
  118. return;
  119. self->monsterinfo.attack_finished = level.time + 2;
  120. if (self->message)
  121. {
  122. gi.centerprintf (other, self->message);
  123. // fixme - put this sound back??
  124. // gi.sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
  125. }
  126. }
  127. /*QUAKED func_door_secret2 (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot slide_right slide_forward
  128. Basic secret door. Slides back, then to the left. Angle determines direction.
  129. FLAGS:
  130. open_once = not implemented yet
  131. 1st_left = 1st move is left/right of arrow
  132. 1st_down = 1st move is forwards/backwards
  133. no_shoot = not implemented yet
  134. always_shoot = even if targeted, keep shootable
  135. reverse_left = the sideways move will be to right of arrow
  136. reverse_back = the to/fro move will be forward
  137. VALUES:
  138. wait = # of seconds before coming back (5 default)
  139. dmg = damage to inflict when blocked (2 default)
  140. */
  141. void SP_func_door_secret2 (edict_t *ent)
  142. {
  143. vec3_t forward,right,up;
  144. float lrSize, fbSize;
  145. ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
  146. ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
  147. ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
  148. if (!ent->dmg)
  149. ent->dmg = 2;
  150. AngleVectors(ent->s.angles, forward, right, up);
  151. VectorCopy(ent->s.origin, ent->move_origin);
  152. VectorCopy(ent->s.angles, ent->move_angles);
  153. G_SetMovedir (ent->s.angles, ent->movedir);
  154. ent->movetype = MOVETYPE_PUSH;
  155. ent->solid = SOLID_BSP;
  156. gi.setmodel (ent, ent->model);
  157. if(ent->move_angles[1] == 0 || ent->move_angles[1] == 180)
  158. {
  159. lrSize = ent->size[1];
  160. fbSize = ent->size[0];
  161. }
  162. else if(ent->move_angles[1] == 90 || ent->move_angles[1] == 270)
  163. {
  164. lrSize = ent->size[0];
  165. fbSize = ent->size[1];
  166. }
  167. else
  168. {
  169. gi.dprintf("Secret door not at 0,90,180,270!\n");
  170. }
  171. if(ent->spawnflags & SEC_MOVE_FORWARD)
  172. VectorScale(forward, fbSize, forward);
  173. else
  174. {
  175. VectorScale(forward, fbSize * -1 , forward);
  176. }
  177. if(ent->spawnflags & SEC_MOVE_RIGHT)
  178. VectorScale(right, lrSize, right);
  179. else
  180. {
  181. VectorScale(right, lrSize * -1, right);
  182. }
  183. if(ent->spawnflags & SEC_1ST_DOWN)
  184. {
  185. VectorAdd(ent->s.origin, forward, ent->moveinfo.start_origin);
  186. VectorAdd(ent->moveinfo.start_origin, right, ent->moveinfo.end_origin);
  187. }
  188. else
  189. {
  190. VectorAdd(ent->s.origin, right, ent->moveinfo.start_origin);
  191. VectorAdd(ent->moveinfo.start_origin, forward, ent->moveinfo.end_origin);
  192. }
  193. ent->touch = secret_touch;
  194. ent->blocked = secret_blocked;
  195. ent->use = fd_secret_use;
  196. ent->moveinfo.speed = 50;
  197. ent->moveinfo.accel = 50;
  198. ent->moveinfo.decel = 50;
  199. if (!ent->targetname || ent->spawnflags & SEC_YES_SHOOT)
  200. {
  201. ent->health = 1;
  202. ent->max_health = ent->health;
  203. ent->takedamage = DAMAGE_YES;
  204. ent->die = fd_secret_killed;
  205. }
  206. if (!ent->wait)
  207. ent->wait = 5; // 5 seconds before closing
  208. gi.linkentity(ent);
  209. }
  210. // ==================================================
  211. #define FWALL_START_ON 1
  212. void force_wall_think(edict_t *self)
  213. {
  214. if(!self->wait)
  215. {
  216. gi.WriteByte (svc_temp_entity);
  217. gi.WriteByte (TE_FORCEWALL);
  218. gi.WritePosition (self->pos1);
  219. gi.WritePosition (self->pos2);
  220. gi.WriteByte (self->style);
  221. gi.multicast (self->offset, MULTICAST_PVS);
  222. }
  223. self->think = force_wall_think;
  224. self->nextthink = level.time + 0.1;
  225. }
  226. void force_wall_use (edict_t *self, edict_t *other, edict_t *activator)
  227. {
  228. if(!self->wait)
  229. {
  230. self->wait = 1;
  231. self->think = NULL;
  232. self->nextthink = 0;
  233. self->solid = SOLID_NOT;
  234. gi.linkentity( self );
  235. }
  236. else
  237. {
  238. self->wait = 0;
  239. self->think = force_wall_think;
  240. self->nextthink = level.time + 0.1;
  241. self->solid = SOLID_BSP;
  242. KillBox(self); // Is this appropriate?
  243. gi.linkentity (self);
  244. }
  245. }
  246. /*QUAKED func_force_wall (1 0 1) ? start_on
  247. A vertical particle force wall. Turns on and solid when triggered.
  248. If someone is in the force wall when it turns on, they're telefragged.
  249. start_on - forcewall begins activated. triggering will turn it off.
  250. style - color of particles to use.
  251. 208: green, 240: red, 241: blue, 224: orange
  252. */
  253. void SP_func_force_wall(edict_t *ent)
  254. {
  255. gi.setmodel (ent, ent->model);
  256. ent->offset[0] = (ent->absmax[0] + ent->absmin[0]) / 2;
  257. ent->offset[1] = (ent->absmax[1] + ent->absmin[1]) / 2;
  258. ent->offset[2] = (ent->absmax[2] + ent->absmin[2]) / 2;
  259. ent->pos1[2] = ent->absmax[2];
  260. ent->pos2[2] = ent->absmax[2];
  261. if(ent->size[0] > ent->size[1])
  262. {
  263. ent->pos1[0] = ent->absmin[0];
  264. ent->pos2[0] = ent->absmax[0];
  265. ent->pos1[1] = ent->offset[1];
  266. ent->pos2[1] = ent->offset[1];
  267. }
  268. else
  269. {
  270. ent->pos1[0] = ent->offset[0];
  271. ent->pos2[0] = ent->offset[0];
  272. ent->pos1[1] = ent->absmin[1];
  273. ent->pos2[1] = ent->absmax[1];
  274. }
  275. if(!ent->style)
  276. ent->style = 208;
  277. ent->movetype = MOVETYPE_NONE;
  278. ent->wait = 1;
  279. if(ent->spawnflags & FWALL_START_ON)
  280. {
  281. ent->solid = SOLID_BSP;
  282. ent->think = force_wall_think;
  283. ent->nextthink = level.time + 0.1;
  284. }
  285. else
  286. ent->solid = SOLID_NOT;
  287. ent->use = force_wall_use;
  288. ent->svflags = SVF_NOCLIENT;
  289. gi.linkentity(ent);
  290. }