commit 9dc55483c0f3873a6905d0f6181191a104b12cb1 Author: archive Date: Wed Jun 24 00:00:00 1998 +0000 as released 1998-06-24 diff --git a/MG_AI.hc b/MG_AI.hc new file mode 100644 index 0000000..ab030d8 --- /dev/null +++ b/MG_AI.hc @@ -0,0 +1,1222 @@ +/* +================================================================== +MG_AI.HC + +Michael Gummelt Artificial Intelligence Routines!!! +US Patent# 2.56734376314532533 + E17 +Hoo-hah! +================================================================== +*/ + +/* +============================================== + +GENERAL + +============================================== +*/ +/* +============= +get_visibility + +Checks for drf_translucent and abslight of an object, +and uses that and it's world lighting value to set it's +visibility value +>=1 = Totally visible (default) +. +. +. +<=0 = Totally invisible +This value should be used in monster aiming as well. + +NOTE: This only works on players since light_level info + is taken from player's weaponmodel lighting (0-255) +============= +*/ +void get_visibility (entity targ , float range_mod) +{ +//NOTE: incorporate distance? +float base, divider, attack_mod; + +//FIXME: .light_level gives a value of 0 if MLS_POWERMODE is on... +//Temp fix for now... + if(targ.classname!="player"||targ.drawflags&MLS_POWERMODE) + { + targ.visibility=1; + return; + } + + if(targ.effects&EF_NODRAW) + { + targ.visibility=0; + return; + } + + if(targ.drawflags&DRF_TRANSLUCENT&&targ.frozen<=0) + { + if(targ.model=="models/assassin.mdl") + divider=3+targ.level;//Bonus for hiding in shadows + else + divider=3; //Makes it 3 times harder to see + } + else + divider=1; + + if(self.classname=="monster_pirhana"||self.classname=="monster_mezzoman") + base = 2;//pirhana and mezzomen see well, even in dark + else if(targ.drawflags&MLS_ABSLIGHT) + base=targ.abslight/2.5; + else + base = 0.8;//light_lev not set right in HW + //base=targ.light_level/75;//75 is semi-fullbright + + if(range_mod) + range_mod=vlen(targ.origin-self.origin)/333; + else + range_mod = 1; + + if(targ.last_attack>time - 3)//Remember where they were when fired + attack_mod=time - targ.last_attack; + + targ.visibility=base/divider/range_mod + attack_mod; +} + +/* +============= +float visibility_good (entity targ,float chance_mod) +MG +Does a random check to see if self can see the target based +it's visibility (calls get_visibility for that targ first) +The higher the chance_mod, the lower the chance of +good visibility. +============= +*/ +float visibility_good (entity targ,float chance_mod) +{ + if(!targ) + return FALSE; + get_visibility(targ,TRUE); + if(random(chance_mod)256) + ignore_height=FALSE; + + +//also check to make sure you can't walkmove forward + if(self.jump_flag>time) //Don't jump too many times in a row + { +// dprint("just jumped\n"); + return FALSE; + } + else if(pointcontents(self.goalentity.origin)!=CONTENT_EMPTY) + { +// dprint("goalentity in water or lava\n"); + return FALSE; + } + else if(!visible(self.goalentity)) + { +// dprint("can't see goalentity\n"); + return FALSE; + } + else if(!ignore_height&&self.goalentity.absmin_z+36>=self.absmin_z&&self.classname!="monster_mezzoman")//SpiderJumpBegin + { +// dprint("not above goalentity, and not spider\n"); + return FALSE; + } + else if(!self.flags&FL_ONGROUND) + { +// dprint("not on ground\n"); + return FALSE; + } + else if(!self.goalentity.flags&FL_ONGROUND&&self.goalentity.classname!="waypoint") + { +// dprint("goalentity in air\n"); + return FALSE; + } + else if(!infront(self.goalentity)) + { +// dprint("goalentity not in front\n"); + return FALSE; + } + else if(vlen(spot1-spot2)>777&&!ignore_height) + { +// dprint("too far away\n"); + return FALSE; + } + else if(vlen(spot1-spot2)<=100)//&&self.think!=SpiderMeleeBegin) + { +// dprint("too close & not spider\n"); + return FALSE; + } + +// if(self.think==SpiderJumpBegin) +// jump_height=vlen((self.goalentity.absmax+self.goalentity.absmin)*0.5-self.origin)/13; +// else + if(self.classname=="monster_mezzoman") + if(self.goalentity.absmin_z>=self.absmin_z+36) + { + jump_height=vlen((self.goalentity.absmax+self.goalentity.absmin)*0.5-self.origin)/13; + jumpup=TRUE; + } + else if(self.goalentity.absmin_z>self.absmin_z - 36) + { + if(ignore_height) + jump_height=vlen((self.goalentity.absmax+self.goalentity.absmin)*0.5-self.origin)/13; + else +// dprint("Mezzo: Goal not above and not below\n"); + return FALSE; + } + + spot1=self.origin; + spot1_z=self.absmax_z; + spot2=spot1; + spot2_z+=36; + + traceline(spot1, spot2,FALSE,self); + + if(trace_fraction<1) + { +// dprint("not enough room above\n"); + return FALSE; + } + + if(!jumpup) + { +// spot1+=normalize(v_forward)*((self.maxs_x+self.maxs_y)*0.5); + spot1+=jumpdir*((self.maxs_x+self.maxs_y)*0.5); + + traceline(self.origin, spot1 + '0 0 36',FALSE,self); + + if(trace_fraction<1) + { +// dprint("not enough room in front\n"); + return FALSE; + } + + traceline(spot1,spot1+jumpdir*64 - '0 0 500',FALSE,self); + + if(pointcontents(trace_endpos)==CONTENT_WATER||pointcontents(trace_endpos)==CONTENT_SLIME||pointcontents(trace_endpos)==CONTENT_LAVA) + { +// dprint("won't jump in water\n"); + return FALSE; + } + } + + ai_face(); +// self.ideal_yaw=jumpdir_y; +// ChangeYaw(); +// if(self.think!=SpiderJumpBegin) +// { + self.jump_flag=time + 7; //Only try to jump once every 7 seconds + SightSound(); + if(!jumpup) + { + self.velocity=jumpdir*jump_height*17*self.scale; + self.velocity_z = jump_height*12*self.scale; + } + else + { + self.velocity=jumpdir*jump_height*10*self.scale; + self.velocity_z = jump_height*14*self.scale; + } + self.flags(-)FL_ONGROUND; + if(self.th_jump) + self.th_jump(); + else + thinktime self : 0.3; +/* } + else + { + self.level=jump_height; + return TRUE; + }*/ +} + +/* +==================================================================== +void MonsterCheckContents () +MG +Monsters check to see if they're in lava or under water and +do damage do themselves if appropriate. +void do_contents_dam () +Just spawns a temporary ent to damage self, using T_Damage on +self does weird stuff- won't kill self, just become invincible +==================================================================== +*/ +void do_contents_dam () +{ + T_Damage(self.enemy,world,world,self.dmg); + if(self.dmg==5) + { + self.classname="contents damager"; + setorigin(self,self.enemy.origin+self.enemy.view_ofs); +// DeathBubbles(1); + } + remove(self); +} + +void MonsterCheckContents () +{ + if(random()>0.3) + return; + + if(pointcontents(self.origin)==CONTENT_LAVA) + { + if(self.flags&FL_FIREHEAL) + { + if(self.health0.05&&self.movetype==MOVETYPE_STEP) + self.flags(-)FL_ONGROUND; + if(trace_fraction==1) + return; + slope=trace_plane_normal; + } + new_angles=vectoangles(slope); + new_angles_x=(90-new_angles_x)*-1;//Gets actual slope + new_angles2='0 0 0'; + new_angles2_y=new_angles_y; + + makevectors(new_angles2); + + mod=v_forward*old_right; + if(mod<0) + mod=1; + else + mod=-1; + + dot=v_forward*old_forward; + self.angles_x=dot*new_angles_x; + self.angles_z=(1-fabs(dot))*new_angles_x*mod; +} +/* +============================================== + +IMP + +============================================== +*/ + +/* +================================================================ +checkenemy() +Checks to see if enemy is of the same monstertype and old enemy +is alive and visible. If so, changes back to it's last enemy. +================================================================ +*/ +void checkenemy (void) +{ +entity oldtarget; +/* if(self.enemy==world) + { + if(!LocateTarget()) + { + if(self.controller.classname=="player") + self.enemy=self.controller; + else + { + self.enemy=world; + self.think=self.th_stand; + } + } + self.goalentity=self.enemy; + return; + } +*/ + if(self.enemy.classname=="player"&&self.enemy.flags2&FL_ALIVE&&self.enemy!=self.controller) + return; + + if (!self.enemy.flags2&FL_ALIVE||self.enemy==self.controller) + { + if(self.controller.classname=="player") + { + self.enemy = self.controller; + self.goalentity=self.enemy; + } + else + self.enemy = world; + + if (self.oldenemy.flags2&FL_ALIVE) + { + self.enemy = self.oldenemy; + self.goalentity = self.enemy; + self.think = self.th_run; + } + else if(LocateTarget()) + { + self.goalentity = self.enemy; + self.think = self.th_run; + } + else + { + if(self.controller.classname=="player") + self.goalentity=self.enemy=self.controller; + else + self.goalentity=self.enemy=world; + + if (self.pathentity) + self.think=self.th_walk; + else + self.think=self.th_stand; + } + thinktime self : 0; + return; + } + + if(self.classname=="monster_imp_lord") + return; + + if(self.oldenemy.classname=="player"&&(self.oldenemy.flags2&FL_ALIVE)&&visible(self.oldenemy)) + { + if((self.model=="models/spider.mdl"||self.model=="models/scorpion.mdl")&&self.enemy.model==self.model) + self.enemy=self.oldenemy; + else + { + oldtarget=self.enemy; + self.enemy=self.oldenemy; + self.oldenemy=oldtarget; + } + self.goalentity=self.enemy; + } +} + +/* +================================================================ +fov() + +Field-Of-View + +Returns TRUE if vector from entity "from" to entity "targ" is +within "scope" degrees of entity "from"'s forward angle. +================================================================ +*/ +float fov(entity targ,entity from,float scope) +{ +vector spot1,spot2; +float dot; + spot1=from.origin+from.view_ofs; + + if(targ.classname=="player") + spot2=targ.origin+targ.proj_ofs; + else + spot2=(targ.absmin+targ.absmax)*0.5; + + makevectors(from.angles); + +// scope=1 - (scope/180);//converts angles into % + dot=normalize(spot2-spot1)*v_forward; + dot=180 - (dot*180); +// dprintf("FOV value : %s\n",dot); + if(dot<=scope) + return TRUE; + + return FALSE; +} + +/* +================================================================ +check_pos_enemy() +MG +Checks to see if enemy is visible, if so, remember the spot for +waypoints, else set your waypoint at the last spot you saw him. +Also resets search_time timer if you see him. +================================================================ +*/ +void check_pos_enemy () +{ + if(!self.mintel) + return; + + if(!visible(self.enemy)) + { + self.attack_state = AS_STRAIGHT; + SetNextWaypoint(); + if(self.model=="models/imp.mdl") //Imps keep looking in general area for a while + if(self.search_time=THINGTYPE_WEBS) + traceline (trace_endpos, destiny, FALSE, trace_ent); + + if (trace_ent == targ) + return TRUE; + + if(whole_body) + { + if(self.attack_state!=AS_FERRY) + self.attack_state = AS_SLIDING; + return FALSE; + } + + if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + {//Don't have a clear shot, and don't want to shoot obstruction + self.attack_state = AS_SLIDING; + return FALSE; + } + + return TRUE; +} + +/* +================================================================ +check_view(entity targ,vector org,vector dir,float dist,float interval) +MG +Will see if it can see the targ entity along the dir +given to it- used to determine which direction a monster +should move in to get a clear line of sight to the targ. +Returns the distance it took to see targ, FALSE if couldn't. +================================================================ +*/ +float check_view(entity targ,vector org,vector dir,float dist,float interval) +{ +float dist_counter; + newmis=spawn(); + dir=normalize(dir); + while(dist_countermaxspeed) + go_dist=maxspeed; + else if(go_distmaxdist) + if(goaldist>0) + goaldist=maxdist; + else + goaldist=maxdist*-1; + if(!movestep(0,0,goaldist, FALSE)) + return FALSE; + } + return TRUE; +} + +/* +==================================================================== + +MEDUSA + +==================================================================== +*/ + +/* +============================================================ +float lineofsight(entity targ, entity from) +MG +Traces a line along "from"'s view_ofs along v_forward and returns +VRAI if it hits targ, FAUX if not, mon ami. +============================================================ +*/ +float lineofsight(entity targ, entity from) +{ +//FIXME: account for monster's lack of pitch if z diff +vector org,dir; + if(from.classname=="player") + makevectors(from.v_angle); +/* else if(from.classname=="monster_medusa") + makevectors(from.angles+from.angle_ofs); +*/ else + makevectors(from.angles); + + org=from.origin+from.view_ofs; + + dir=normalize(v_forward); + + traceline(org, org+dir*1000,FALSE,from); + + if(trace_ent!=targ) + return FALSE; + else + { +// dprint("Line of sight from "); +// dprint(from.classname); +// dprint(" to "); +// dprint(targ.classname); +// dprint(" confirmed\n"); + return TRUE; + } +} + +/* +==================================================================== + +EIDOLON + +==================================================================== +*/ + +/* +===================================================== +entity riderpath_findbest(entity subject_path) +MG +Returns closest rider path corner that "subject_path" +leads to. Used for Rider Bosses. +===================================================== +*/ +entity riderpath_findbest(entity subject_path) +{ +entity search,found,best_path; +float next,num_points,position,bestdist,lastdist; + + num_points = 0; + if (subject_path.next_path_1) + num_points += 1; + if (subject_path.next_path_2) + num_points += 1; + if (subject_path.next_path_3) + num_points += 1; + if (subject_path.next_path_4) + num_points += 1; + if (subject_path.next_path_5) + num_points += 1; + if (subject_path.next_path_6) + num_points += 1; + + if (!num_points) + { + dprintf("rider path %s has no next points\n",subject_path.path_id); + remove(self); + return world; + } + + bestdist=vlen(self.goalentity.origin-self.origin); + lastdist=bestdist; + position=0; + best_path=world; + while(position0) + { + traceline(startpos,startpos-'0 0 18',TRUE,self); + if(trace_fraction==1) + return FALSE; + startpos+=dir*5; + diff_count-=1; + } + return TRUE; +} + +/* +====================================================== +float check_heading_left_or_right (entity object) +MG +Will check to see if the given object will be to +the left or the right of self once it gets to +self. Uses it's current position and extrapolates +based on it's heading (velocity). +Will return: +1 = left +-1 = right +0 = neither. +Special case: If called by a monster that's not + awake, will return opposite of these assuming + that the monster wants to cut off player- + only used by the Rolling Ambush Mezzomen. +====================================================== +*/ +float check_heading_left_or_right (entity object) +{ +vector spot1, spot2, vec; +float dot, rng, reverse; + + makevectors (self.angles); + spot1 = self.origin + self.view_ofs; + spot2 = object.origin; +//To get the eventual location of the projectile when it gets to him... + rng=vlen(spot1-spot2); + spot2+=normalize(object.velocity)*(rng+15);//Add a bit for good measure + + vec = normalize (spot2 - spot1); +//FIXME? What about behind me? + + if(object.classname=="player"&&!self.monster_awake) + { + self.monster_awake=TRUE; + sound(self,CHAN_VOICE,"mezzo/attack.wav",1,ATTN_NORM); + reverse=-1; + } + else + reverse=1; + + dot = vec * v_right; + if ( dot > 0) + return -1*reverse; + + dot = vec * (v_right*-1); + if ( dot > 0) + return 1*reverse; + + return 0; +} + +/* +====================================================== +float navigate (float walkspeed) +MG +Checks to see which side of the entity is blocked +and will move in the opposite direction using +walkmove (for left-right) or movestep (for up-down) +if it can. Will move the specified distance. +If it can't move that way or it doesn't find a blocked +side, it returns false. + +Meant for use with flying and swimming monsters +because movetogoal doesn't make them navigate! +====================================================== +*/ +float navigate (float walkspeed) +{ +vector checkdir,org,new_angle; +float vert_size,horz_size; + makevectors(self.angles); + checkdir=v_right; + org=self.origin+checkdir*self.size_x; + vert_size=self.size_z/2; + horz_size=(self.size_x+self.size_y)/4; + traceline(org,org+v_forward*horz_size,FALSE,self); + if(trace_fraction==1&&!trace_allsolid) + { + checkdir=v_right*-1; + org=self.origin+checkdir*horz_size; + traceline(org,org+v_forward*horz_size,FALSE,self); + } + if(self.flags&FL_FLY||self.flags&FL_SWIM) + { + if(trace_fraction==1&&!trace_allsolid) + { + checkdir=v_up; + org=self.origin+checkdir*vert_size; + traceline(org,org+v_forward*horz_size,FALSE,self); + } + if(trace_fraction==1&&!trace_allsolid) + { + checkdir=v_up*-1; + org=self.origin+checkdir*vert_size; + traceline(org,org+v_forward*horz_size,FALSE,self); + } + } + if(trace_fraction<1||trace_allsolid) + { + if(checkdir==v_right||checkdir==v_right*-1) + { + new_angle=vectoangles(checkdir*-1); + if(!walkmove(new_angle_y,walkspeed,FALSE)) + { +// dprint("Couldn't Side-step\n"); + return FALSE; + } +// dprint("Side-stepped\n"); + return TRUE; + } + if(checkdir==v_up) + walkspeed*=-1; + if(!movestep(0,0,walkspeed,FALSE)) + { +// dprint("couldn't move up/down\n"); + return FALSE; + } +// dprint("up-down move\n"); + return TRUE; + } +// dprint("Not blocked\n"); + return FALSE;//FOUND NO BLOCKING!!! +} + +/* +============================================================= +vector extrapolate_pos_for_speed (vector p1,float pspeed,entity targ,float accept) +MG +Estimates where the "targ" will be by the time a projectile +travelling at "pspeed" leaving "org" arrives at "targ"'s origin. +It then calculates a new spot to shoot at so that the +projectile will arrive at such spot at the same time as +"targ". Will return '0 0 0' (FALSE) if there is not a clear +line of fire to the spot or if the new vector is out of the +acceptable range (based on dot product of original vec and +the new vec). +============================================================= +*/ +vector extrapolate_pos_for_speed (vector p1,float pspeed,entity targ,float accept) +{ +float dist1,dist2,tspeed,dot,eta1,eta2,eta_delta,failed; +vector p2,p3,targ_dir,vec1,vec2; + +// dprint("Extrapolating\n"); + p2=targ.origin+targ.view_ofs; //current target viewport + vec1=p2 - p1; //vector to p2 + dist1=vlen(vec1); //distance to p2 + vec1=normalize(vec1); //direction to p2 + targ_dir=targ.velocity; //target velocity + tspeed=vlen(targ_dir); //target speed + targ_dir=normalize(targ_dir); //target direction + + eta1=dist1/pspeed; //Estimated time of arrival of projectile to p2 + + p3=p2 + targ_dir * tspeed * eta1; //Extrapolated postion of targ at time + eta1 + dist2=vlen(p3-p1); //new distance to p3 + + eta2=dist2/pspeed; //ETA of projectile to p3 + eta_delta=eta2-eta1; //change in ETA's + + p3+=targ_dir*tspeed*eta_delta*random();//Add any diff in ETA to p3's location,random a little in case they slow down + + traceline(p1,p3,FALSE,self); + if(trace_fraction<1) + { + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, p3, FALSE, trace_ent); + if(trace_fraction<1) + if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + {//Don't have a clear shot, and don't want to shoot obstruction + // dprint("No clear shot\n"); + self.attack_state = AS_SLIDING; + failed=TRUE; + } + } + + vec2=normalize(p3-p1); //New vector to p3 + dot=vec1*vec2; + if(dot0) + { + vofs=v_up*0.5*random(0-ofs,ofs)+v_right*1.5*random(0-ofs,ofs); + return vofs; + } + return '0 0 0'; +} diff --git a/acidorb.hc b/acidorb.hc new file mode 100644 index 0000000..f80675d --- /dev/null +++ b/acidorb.hc @@ -0,0 +1,522 @@ +/* +============================================================================== + +Q:\art\models\weapons\spllbook\spllbook.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\spllbook +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame idlebn01 idlebn02 idlebn03 idlebn04 idlebn05 +$frame idlebn06 idlebn07 idlebn08 idlebn09 idlebn10 +$frame idlebn11 idlebn12 idlebn13 idlebn14 idlebn15 +$frame idlebn16 idlebn17 idlebn18 idlebn19 idlebn20 +$frame idlebn21 idlebn22 idlebn23 idlebn24 idlebn25 + +// +$frame idlean26 idlean27 idlean28 idlean29 idlean30 +$frame idlean31 idlean32 idlean33 idlean34 idlean35 +$frame idlean36 idlean37 idlean38 idlean39 idlean40 +$frame idlean41 idlean42 idlean43 idlean44 idlean45 +$frame idlean46 idlean47 idlean48 idlean49 idlean50 + +// +$frame normal51 normal52 normal53 normal54 normal55 +$frame normal56 normal57 normal58 normal59 normal60 +$frame normal61 normal62 normal63 normal64 + +// +$frame topowr65 topowr66 topowr67 topowr68 topowr69 +$frame topowr70 topowr71 topowr72 topowr73 topowr74 +$frame topowr75 topowr76 topowr77 topowr78 topowr79 +$frame topowr80 topowr81 topowr82 topowr83 topowr84 + +// +$frame pidleb085 pidleb086 pidleb087 pidleb088 pidleb089 +$frame pidleb090 pidleb091 pidleb092 pidleb093 pidleb094 +$frame pidleb095 pidleb096 pidleb097 pidleb098 pidleb099 +$frame pidleb100 pidleb101 pidleb102 pidleb103 pidleb104 +$frame pidleb105 pidleb106 pidleb107 pidleb108 pidleb109 + +// +$frame pidlea110 pidlea111 pidlea112 pidlea113 pidlea114 +$frame pidlea115 pidlea116 pidlea117 pidlea118 pidlea119 +$frame pidlea120 pidlea121 pidlea122 pidlea123 pidlea124 +$frame pidlea125 pidlea126 pidlea127 pidlea128 pidlea129 +$frame pidlea130 pidlea131 pidlea132 pidlea133 pidlea134 + +// +$frame powern135 powern136 powern137 powern138 powern139 +$frame powern140 powern141 powern142 powern143 powern144 +$frame powern145 powern146 powern147 powern148 + +// +$frame tonrml149 tonrml150 tonrml151 tonrml152 tonrml153 +$frame tonrml154 tonrml155 tonrml156 tonrml157 tonrml158 +$frame tonrml159 tonrml160 tonrml161 tonrml162 tonrml163 +$frame tonrml164 tonrml165 tonrml166 tonrml167 tonrml168 +// +$frame ndesel213 ndesel214 ndesel215 ndesel216 ndesel217 +$frame ndesel218 ndesel219 ndesel220 ndesel221 ndesel222 +$frame ndesel223 + +// +$frame pselon224 pselon225 pselon226 pselon227 pselon228 +$frame pselon229 pselon230 pselon231 pselon232 pselon233 +$frame pselon234 + + + +/*void acidblobFizzle (void) +{ + CreateGreenSmoke (self.origin,'0 0 8',HX_FRAME_TIME * 2); + remove(self); +} +*/ +void acidBlobDie(void) +{ + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_ACIDBLOB); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 10); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 10); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 10); + multicast(self.origin,MULTICAST_PHS_R); + + remove(self); +} + +void acidblobThink (void) +{ + if(self.lifetimetime) + return; + + FireAcidBlob("acidblob"); + self.attack_finished=time+0.7; +} + +void aorb_normal() +{ + if(self.attack_finished>time) + return; + + FireAcidMissile(0); + self.attack_finished=time+0.4; +} + +/*====================== +ACTION +select +deselect +ready loop +relax loop +fire once +fire loop +ready to relax(after short delay) +relax to ready(Fire delay? or automatic if see someone?) +=======================*/ + +void()acidorb_ready_power; +void()acidorb_ready_normal; +void() Suc_Aorb_Fire; + +void acidorb_fire (void) +{ + if(self.button0&&self.weaponframe==$normal60 &&!self.artifact_active&ART_TOMEOFPOWER) + self.weaponframe=$normal58; + else + if(self.artifact_active&ART_TOMEOFPOWER) + { + self.wfs = advanceweaponframe($powern135,$powern148); + if(self.weaponframe<$powern141) + self.weaponframe+=1; + } + else + { + self.wfs = advanceweaponframe($normal51,$normal64); + if(self.weaponframe<$normal58) + self.weaponframe+=1; + } + self.th_weapon=acidorb_fire; + self.last_attack=time; + if(self.wfs==WF_CYCLE_WRAPPED||self.bluemana<3||(self.bluemana<8&&self.artifact_active&ART_TOMEOFPOWER)) + if(self.artifact_active&ART_TOMEOFPOWER) + acidorb_ready_power(); + else + acidorb_ready_normal(); + else if(self.weaponframe==$normal58)// &&self.attack_finished<=time) + aorb_normal(); + else if(self.weaponframe==$powern141) + aorb_power();//Fixme: hold this frame for a few +} + +void Suc_Aorb_Fire() +{ + acidorb_fire(); + + thinktime self : 0; +} + +void acidorb_jellyfingers_normal () +{ + self.wfs = advanceweaponframe($idlebn01,$idlebn25); + self.th_weapon=acidorb_jellyfingers_normal; + if(self.wfs==WF_CYCLE_WRAPPED) + if(self.artifact_active&ART_TOMEOFPOWER) + acidorb_ready_power(); + else + acidorb_ready_normal(); +} + +void acidorb_jellyfingers_power () +{ + self.wfs = advanceweaponframe($pidleb085,$pidleb109); + self.th_weapon=acidorb_jellyfingers_power; + if(self.wfs==WF_CYCLE_WRAPPED) + if(self.artifact_active&ART_TOMEOFPOWER) + acidorb_ready_power(); + else + acidorb_ready_normal(); +} + +void acidorb_to_power (void) +{ + self.wfs = advanceweaponframe($topowr65,$topowr84); + self.th_weapon=acidorb_to_power; + if(self.wfs==WF_CYCLE_WRAPPED) + acidorb_ready_power(); +} + +void acidorb_to_normal (void) +{ + self.wfs = advanceweaponframe($tonrml149,$tonrml168); + self.th_weapon=acidorb_to_normal; + if(self.wfs==WF_CYCLE_WRAPPED) + acidorb_ready_normal(); +} + +void acidorb_ready_normal (void) +{ + self.wfs = advanceweaponframe($idlean26,$idlean50); + if(random()<0.1&&self.weaponframe==$idlean50) + self.th_weapon=acidorb_jellyfingers_normal; + else + self.th_weapon=acidorb_ready_normal; + if(self.artifact_active&ART_TOMEOFPOWER) + { + self.weaponframe=$topowr65; + acidorb_to_power(); + } +} + +void acidorb_ready_power (void) +{ + self.wfs = advanceweaponframe($pidlea110,$pidlea134); + if(random()<0.1&&self.weaponframe==$pidlea134) + self.th_weapon=acidorb_jellyfingers_power; + else + self.th_weapon=acidorb_ready_power; + if(!self.artifact_active&ART_TOMEOFPOWER) + { + self.weaponframe=$tonrml149; + acidorb_to_normal(); + } +} + +void acidorb_select_normal (void) +{ + self.wfs = advanceweaponframe($ndesel223,$ndesel213); + self.weaponmodel = "models/sucwp2.mdl"; + self.th_weapon=acidorb_select_normal; + self.t_width=-1; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + acidorb_ready_normal(); + } +} + +void acidorb_select_power (void) +{ + self.wfs = advanceweaponframe($pselon224,$pselon234); + self.weaponmodel = "models/sucwp2.mdl"; + self.th_weapon=acidorb_select_power; + self.t_width=-1; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + acidorb_ready_power(); + } +} + +void acidorb_select (void) +{ + if(self.artifact_active&ART_TOMEOFPOWER) + acidorb_select_power(); + else + acidorb_select_normal(); +} + +void acidorb_deselect_normal (void) +{ + self.wfs = advanceweaponframe($ndesel213,$ndesel223); + self.th_weapon=acidorb_deselect_normal; + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + +void acidorb_deselect_power (void) +{ + self.wfs = advanceweaponframe($pselon234,$pselon224); + self.th_weapon=acidorb_deselect_power; + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + +void acidorb_deselect (void) +{ + if(self.artifact_active&ART_TOMEOFPOWER) + acidorb_deselect_power(); + else + acidorb_deselect_normal(); +} + diff --git a/ai.hc b/ai.hc new file mode 100644 index 0000000..11e515f --- /dev/null +++ b/ai.hc @@ -0,0 +1,779 @@ +/* + * $Header: /HexenWorld/Siege/Ai.hc 10 5/25/98 1:38p Mgummelt $ + */ +void(entity etemp, entity stemp, entity stemp, float dmg) T_Damage; +/* + +.enemy +Will be world if not currently angry at anyone. + +.pathcorner +The next path spot to walk toward. If .enemy, ignore .pathcorner +When an enemy is killed, the monster will try to return to it's path. + +.hunt_time +Set to time + something when the player is in sight, but movement straight for +him is blocked. This causes the monster to use wall following code for +movement direction instead of sighting on the player. + +.ideal_yaw +A yaw angle of the intended direction, which will be turned towards at up +to 45 deg / state. If the enemy is in view and hunt_time is not active, +this will be the exact line towards the enemy. + +.pausetime +A monster will leave it's stand state and head towards it's .pathcorner when +time > .pausetime. + +walkmove(angle, speed) primitive is all or nothing +*/ + +//float ArcherCheckAttack (void); +//float MedusaCheckAttack (void); +void()SetNextWaypoint; +//void()SpiderMeleeBegin; +//void()spider_onwall_wait; +float(entity targ , entity from)infront_of_ent; +void(entity proj)mezzo_choose_roll; +//void()hive_die; + +//void()check_climb; + +// +// globals +// +float current_yaw; + +// +// when a monster becomes angry at a player, that monster will be used +// as the sight target the next frame so that monsters near that one +// will wake up even if they wouldn't have noticed the player +// +float sight_entity_time; +float(float v) anglemod = +{ + while (v >= 360) + v = v - 360; + while (v < 0) + v = v + 360; + return v; +}; + +//============================================================================ + +/* +============= +range + +returns the range catagorization of an entity reletive to self +0 melee range, will become hostile even if back is turned +1 visibility and infront, or visibility and show hostile +2 infront and show hostile +3 only triggered by damage +============= +*/ +float(entity targ) range = +{ +vector spot1, spot2; +float r,melee; + + if((self.solid==SOLID_BSP||self.solid==SOLID_TRIGGER)&&self.origin=='0 0 0') + spot1=(self.absmax+self.absmin)*0.5; + else + spot1 = self.origin + self.view_ofs; + + if((targ.solid==SOLID_BSP||targ.solid==SOLID_TRIGGER)&&targ.origin=='0 0 0') + spot2=(targ.absmax+targ.absmin)*0.5; + else + spot2 = targ.origin + targ.view_ofs; + + r = vlen (spot1 - spot2); + + if (self.classname=="monster_mummy") + melee = 50; + else + melee = 100; + + if (r < melee) + return RANGE_MELEE; + if (r < 500) + return RANGE_NEAR; + if (r < 1000) + return RANGE_MID; + return RANGE_FAR; +}; + +/* +============= +visible2ent + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +float visible2ent (entity targ, entity forent) +{ +vector spot1, spot2; + if((forent.solid==SOLID_BSP||forent.solid==SOLID_TRIGGER)&&forent.origin=='0 0 0') + spot1=(forent.absmax+forent.absmin)*0.5; + else + spot1 = forent.origin + forent.view_ofs; + + if((targ.solid==SOLID_BSP||targ.solid==SOLID_TRIGGER)&&targ.origin=='0 0 0') + spot2=(targ.absmax+targ.absmin)*0.5; + else + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, TRUE, forent); // see through other monsters + + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, TRUE, trace_ent); +// else if (trace_inopen && trace_inwater)//FIXME? Translucent water? +// return FALSE; // sight line crossed contents + + if (trace_fraction == 1) + { + if(forent.flags&FL_MONSTER) + { + if(visibility_good(targ,0.15 - skill/20)) + return TRUE; + } + else + return TRUE; + } + + return FALSE; +} + +/* +============= +infront_of_ent + +returns 1 if the targ is in front (in sight) of from +============= +*/ +float infront_of_ent (entity targ , entity from) +{ + vector vec,spot1,spot2; + float accept,dot; + + if(from.classname=="player") + makevectors (from.v_angle); +/* else if(from.classname=="monster_medusa") + makevectors (from.angles+from.angle_ofs); +*/ else + makevectors (from.angles); + + if((from.solid==SOLID_BSP||from.solid==SOLID_TRIGGER)&&from.origin=='0 0 0') + spot1=(from.absmax+from.absmin)*0.5; + else + spot1 = from.origin + from.view_ofs; + + spot2=(targ.absmax+targ.absmin)*0.5; + + vec = normalize (spot2 - spot1); + dot = vec * v_forward; + + accept = 0.3; + + if ( dot > accept) + return TRUE; + return FALSE; +} + +/* +============= +visible + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +float visible (entity targ) +{ + return visible2ent(targ,self); +} + +/* +============= +infront + +returns 1 if the entity is in front (in sight) of self +============= +*/ +float infront (entity targ) +{ + return infront_of_ent(targ,self); +} + + +//============================================================================ + +/* +=========== +ChangeYaw + +Turns towards self.ideal_yaw at self.yaw_speed +Sets the global variable current_yaw +Called every 0.1 sec by monsters +============ +*/ +/* + +void ChangeYaw () +{ +float ideal, move; + +//current_yaw = self.ideal_yaw; +// mod down the current angle + current_yaw = anglemod( self.angles_y ); + ideal = self.ideal_yaw; + + + if (current_yaw == ideal) + return; + + move = ideal - current_yaw; + if (ideal > current_yaw) + { + if (move > 180) + move = move - 360; + } + else + { + if (move < -180) + move = move + 360; + } + + if (move > 0) + { + if (move > self.yaw_speed) + move = self.yaw_speed; + } + else + { + if (move < 0-self.yaw_speed ) + move = 0-self.yaw_speed; + } + + current_yaw = anglemod (current_yaw + move); + + self.angles_y = current_yaw; +} + +*/ + + +//============================================================================ + +void() HuntTarget = +{ + self.goalentity = self.enemy; + if(self.spawnflags&PLAY_DEAD) + { +// dprint("getting up!!!\n"); + self.think=self.th_possum_up; + self.spawnflags(-)PLAY_DEAD; + } + else + self.think = self.th_run; +// self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + thinktime self : 0.1; +// SUB_AttackFinished (1); // wait a while before first attack +}; + +void SightSound (void) +{ + if (self.classname == "monster_archer") + sound (self, CHAN_VOICE, "archer/sight.wav", 1, ATTN_NORM); + else if (self.classname == "monster_archer_lord") + sound (self, CHAN_VOICE, "archer/sight2.wav", 1, ATTN_NORM); + else if (self.classname == "monster_mummy") + sound (self, CHAN_WEAPON, "mummy/sight.wav", 1, ATTN_NORM); + else if (self.classname == "monster_mummy_lord") + sound (self, CHAN_WEAPON, "mummy/sight2.wav", 1, ATTN_NORM); + +} + +void() FoundTarget = +{ + if (self.enemy.classname == "player") + { // let other monsters see this monster for a while + sight_entity = self; + sight_entity_time = time + 1; + } + + self.show_hostile = time + 1; // wake up other monsters + + SightSound (); + + HuntTarget (); +}; + +/* +=========== +FindTarget + +Self is currently not attacking anything, so try to find a target + +Returns TRUE if an enemy was sighted + +When a player fires a missile, the point of impact becomes a fakeplayer so +that monsters that see the impact will respond as if they had seen the +player. + +To avoid spending too much time, only a single client (or fakeclient) is +checked each frame. This means multi player games will have slightly +slower noticing monsters. +============ +*/ +float(float dont_hunt) FindTarget = +{ +entity client; +float r; + +// if the first spawnflag bit is set, the monster will only wake up on +// really seeing the player, not another monster getting angry + +// spawnflags & 3 is a big hack, because zombie crucified used the first +// spawn flag prior to the ambush flag, and I forgot about it, so the second +// spawn flag works as well +// if(!deathmatch&&(self.classname=="monster_imp_lord"||self.classname=="cube_of_force")) +// return FindMonsterTarget(); + + if (sight_entity_time >= time&&sight_entity!=world) + { + client = sight_entity; + if (client.enemy == self.enemy) + return TRUE; + } + else + { + client = checkclient (); + if (!client) + return FALSE; // current check entity isn't in PVS + } + +// if(self.classname=="monster_imp_lord"&&client==self.controller) +// return FALSE; + + if (client == self.enemy) + return FALSE; + + if (client.flags & FL_NOTARGET) + return FALSE; + + r = range (client); + if (r == RANGE_FAR) + return FALSE; + + if(self.siege_team) + if(client.siege_team==self.siege_team)//SIEGE + return FALSE; + + if(!visibility_good(client,5)) + { +// dprint("Monster has low visibility on "); +// dprint(client.netname); +// dprintf("(%s)\n",client.visibility); + return FALSE; + } + +// if(self.think!=spider_onwall_wait) + if (r == RANGE_NEAR) + { + if (client.show_hostile < time && !infront (client)) + return FALSE; + } + else if (r == RANGE_MID) + { + if (!infront (client)) + return FALSE; + } + + if (!visible (client)) + return FALSE; + +// +// got one +// + self.enemy = client; + + if (self.enemy.classname != "player") + { + self.enemy = self.enemy.enemy; + if (self.enemy.classname != "player") + { + self.enemy = world; + return FALSE; + } + } + +/* if(self.spawnflags&PLAY_DEAD) + { + if(r==RANGE_MELEE) + { + if(!dont_hunt) + FoundTarget (); + return TRUE; + } + else if(!infront_of_ent(self,self.enemy)&&random()<0.1&&random()<0.1) + { + if(!dont_hunt) + FoundTarget (); + return TRUE; + } + else + { + self.enemy=world; + return FALSE; + } + } +*/ + if(!dont_hunt) + FoundTarget (); + return TRUE; +}; + +//void()SpiderJumpBegin; +//============================================================================= + +void(float dist) ai_forward = +{ + walkmove (self.angles_y, dist, FALSE); +}; + +void(float dist) ai_back = +{ + walkmove ( (self.angles_y+180), dist, FALSE); +}; + + +/* +============= +ai_pain + +stagger back a bit +============= +*/ +void(float dist) ai_pain = +{ +// ai_back (dist); +float away; + + away = vectoyaw (self.origin - self.enemy.origin)+90*random(0.5,-0.5); + + walkmove (away, dist,FALSE); +}; + +/* +============= +ai_painforward + +stagger back a bit +============= +*/ +void(float dist) ai_painforward = +{ + walkmove (self.ideal_yaw, dist, FALSE); +}; + +/* +============= +ai_walk + +The monster is walking it's beat +============= +*/ +void(float dist) ai_walk = +{ + + MonsterCheckContents(); + + movedist = dist; + + // check for noticing a player + if(self.classname!="monster_pirhana") + if (FindTarget (FALSE)) + return; + + movetogoal (dist); +}; + + +/* +============= +ai_stand + +The monster is staying in one place for a while, with slight angle turns +============= +*/ +void() ai_stand = +{ + MonsterCheckContents(); + + if(self.classname!="monster_pirhana") + if (FindTarget (FALSE)) + return; + + if(self.spawnflags&PLAY_DEAD) + return; + + if (time > self.pausetime) + { + self.th_walk (); + return; + } + +// change angle slightly +}; + +/* +============= +ai_turn + +don't move, but turn towards ideal_yaw +============= +*/ +void() ai_turn = +{ + if (FindTarget (FALSE)) + return; + + ChangeYaw (); +}; + +//============================================================================= + +/* +============= +ChooseTurn +============= +*/ +void(vector dest3) ChooseTurn = +{ + local vector dir, newdir; + + dir = self.origin - dest3; + + newdir_x = trace_plane_normal_y; + newdir_y = 0 - trace_plane_normal_x; + newdir_z = 0; + + if (dir * newdir > 0) + { + dir_x = 0 - trace_plane_normal_y; + dir_y = trace_plane_normal_x; + } + else + { + dir_x = trace_plane_normal_y; + dir_y = 0 - trace_plane_normal_x; + } + + dir_z = 0; + self.ideal_yaw = vectoyaw(dir); +}; + +/* +============ +FacingIdeal + +Within angle to launch attack? +============ +*/ +float() FacingIdeal = +{ + local float delta; + + delta = anglemod(self.angles_y - self.ideal_yaw); + if (delta > 45 && delta < 315) + return FALSE; + return TRUE; +}; + + +//============================================================================= + +float() CheckAnyAttack = +{ +// if (self.model=="models/medusa.mdl"||self.model=="models/medusa2.mdl") +// return(MedusaCheckAttack ()); + + if (!enemy_vis) + return FALSE; + +// if (self.model=="models/archer.mdl") +// return(ArcherCheckAttack ()); + + if(self.goalentity==self.controller) + return FALSE; + + return CheckAttack (); +}; + + +/* +============= +ai_attack_face + +Turn in place until within an angle to launch an attack +============= +*/ +void() ai_attack_face = +{ + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + if (FacingIdeal()) // Ready to go get em + { + if (self.attack_state == AS_MISSILE) + self.th_missile (); + else if (self.attack_state == AS_MELEE) + self.th_melee (); + self.attack_state = AS_STRAIGHT; + } +}; + + +/* +============= +ai_run_slide + +Strafe sideways, but stay at aproximately the same range +============= +*/ +void ai_run_slide () +{ +float ofs; + + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + if (self.lefty) + ofs = 90; + else + ofs = -90; + + if (walkmove (self.ideal_yaw + ofs, movedist, FALSE)) + return; + + self.lefty = 1 - self.lefty; + + walkmove (self.ideal_yaw - ofs, movedist, FALSE); +} + + +/* +============= +ai_run + +The monster has an enemy it is trying to kill +============= +*/ +void(float dist) ai_run = +{ + + MonsterCheckContents(); + + movedist = dist; +// see if the enemy is dead + if (!self.enemy.flags2&FL_ALIVE||(self.enemy.artifact_active&ARTFLAG_STONED&&self.classname!="monster_medusa")) + { + self.enemy = world; + // FIXME: look all around for other targets + if (self.oldenemy.health > 0) + { + self.enemy = self.oldenemy; + HuntTarget (); + } + else if(coop) + { + if(!FindTarget(TRUE)) //Look for other enemies in the area + { + if (self.pathentity) + self.th_walk (); + else + self.th_stand (); + return; + } + } + else + { + if (self.pathentity) + self.th_walk (); + else + self.th_stand (); + return; + } + } + + self.show_hostile = time + 1; // wake up other monsters + +// check knowledge of enemy + enemy_vis = visible(self.enemy); + if (enemy_vis) + { + if(self.classname!="monster_pirhana") + self.search_time = time + 5; + if(self.mintel) + { + self.goalentity=self.enemy; + self.wallspot=(self.enemy.absmin+self.enemy.absmax)*0.5; + } + } + else + { + if(coop) + { + if(!FindTarget(TRUE)) + if(self.model=="models/spider.mdl") + { + if(random()<0.5) + SetNextWaypoint(); + } + else + SetNextWaypoint(); + } + if(self.mintel) + if(self.model=="models/spider.mdl") + { + if(random()<0.5) + SetNextWaypoint(); + } + else + SetNextWaypoint(); + } + + if(random()<0.5&&(!self.flags&FL_SWIM)&&(!self.flags&FL_FLY)&&(self.spawnflags&JUMP)) + CheckJump(); + +// look for other coop players + if ((coop||dmMode==DM_SIEGE) && self.search_time < time) + { + if (FindTarget (FALSE)) + return; + } + + enemy_infront = infront(self.enemy); + enemy_range = range(self.enemy); + enemy_yaw = vectoyaw(self.goalentity.origin - self.origin); + + if ((self.attack_state == AS_MISSILE) || (self.attack_state == AS_MELEE)) // turning to attack + { + ai_attack_face (); + return; + } + + if (CheckAnyAttack ()) + return; // beginning an attack + + if (self.attack_state == AS_SLIDING) + { + ai_run_slide (); + return; + } + +// head straight in +// if(self.netname=="spider") +// check_climb(); + movetogoal (dist); // done in C code... +}; + diff --git a/ai2.hc b/ai2.hc new file mode 100644 index 0000000..d452578 --- /dev/null +++ b/ai2.hc @@ -0,0 +1,787 @@ +/* + * $Header: /HexenWorld/Siege/ai2.hc 4 5/25/98 1:38p Mgummelt $ + */ +void(entity etemp, entity stemp, entity stemp, float dmg) T_Damage; +/* + +.enemy +Will be world if not currently angry at anyone. + +.pathcorner +The next path spot to walk toward. If .enemy, ignore .pathcorner +When an enemy is killed, the monster will try to return to it's path. + +.hunt_time +Set to time + something when the player is in sight, but movement straight for +him is blocked. This causes the monster to use wall following code for +movement direction instead of sighting on the player. + +.ideal_yaw +A yaw angle of the intended direction, which will be turned towards at up +to 45 deg / state. If the enemy is in view and hunt_time is not active, +this will be the exact line towards the enemy. + +.pausetime +A monster will leave it's stand state and head towards it's .pathcorner when +time > .pausetime. + +walkmove(angle, speed) primitive is all or nothing +*/ + +void()SetNextWaypoint; +float(entity targ , entity from)infront_of_ent; +float()eidolon_check_attack; +void()multiplayer_health; + +//void()check_climb; + +// +// globals +// +float current_yaw; + +// +// when a monster becomes angry at a player, that monster will be used +// as the sight target the next frame so that monsters near that one +// will wake up even if they wouldn't have noticed the player +// +float sight_entity_time; +void()riderpath_init; +void(float move_speed)riderpath_move; +float(float move_speed)eidolon_riderpath_move; +void() eidolon_guarding; +void()hive_die; +float(float v) anglemod = +{ + while (v >= 360) + v = v - 360; + while (v < 0) + v = v + 360; + return v; +}; + +//============================================================================ + +/* +============= +range + +returns the range catagorization of an entity reletive to self +0 melee range, will become hostile even if back is turned +1 visibility and infront, or visibility and show hostile +2 infront and show hostile +3 only triggered by damage +============= +*/ +float(entity targ) range = +{ + local vector spot1, spot2; + local float r,melee; + + if((self.solid==SOLID_BSP||self.solid==SOLID_TRIGGER)&&self.origin=='0 0 0') + spot1=(self.absmax+self.absmin)*0.5; + else + spot1 = self.origin + self.view_ofs; + + if((targ.solid==SOLID_BSP||targ.solid==SOLID_TRIGGER)&&targ.origin=='0 0 0') + spot2=(targ.absmax+targ.absmin)*0.5; + else + spot2 = targ.origin + targ.view_ofs; + + r = vlen (spot1 - spot2); + + if (self.classname=="monster_mummy") + melee = 50; + else + melee = 100; + + if (r < melee) + return RANGE_MELEE; + if (r < 500) + return RANGE_NEAR; + if (r < 1000) + return RANGE_MID; + return RANGE_FAR; +}; + +/* +============= +visible2ent + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +float visible2ent (entity targ, entity forent) +{ +vector spot1, spot2; + if((forent.solid==SOLID_BSP||forent.solid==SOLID_TRIGGER)&&forent.origin=='0 0 0') + spot1=(forent.absmax+forent.absmin)*0.5; + else + spot1 = forent.origin + forent.view_ofs; + + if((targ.solid==SOLID_BSP||targ.solid==SOLID_TRIGGER)&&targ.origin=='0 0 0') + spot2=(targ.absmax+targ.absmin)*0.5; + else + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, TRUE, forent); // see through other monsters + + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, TRUE, trace_ent); + else if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (trace_fraction == 1) + return TRUE; + + return FALSE; +} + +/* +============= +infront_of_ent + +returns 1 if the targ is in front (in sight) of from +============= +*/ +float infront_of_ent (entity targ , entity from) +{ + vector vec,spot1,spot2; + float accept,dot; + + if(from.classname=="player") + makevectors (from.v_angle); +/* else if(from.classname=="monster_medusa") + makevectors (from.angles+from.angle_ofs); +*/ else + makevectors (from.angles); + + if((from.solid==SOLID_BSP||from.solid==SOLID_TRIGGER)&&from.origin=='0 0 0') + spot1=(from.absmax+from.absmin)*0.5; + else + spot1 = from.origin + from.view_ofs; + + spot2=(targ.absmax+targ.absmin)*0.5; + + vec = normalize (spot2 - spot1); + dot = vec * v_forward; + + accept = 0.3; + + if ( dot > accept) + return TRUE; + return FALSE; +} + +/* +============= +visible + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +float visible (entity targ) +{ + return visible2ent(targ,self); +} + +/* +============= +infront + +returns 1 if the entity is in front (in sight) of self +============= +*/ +float infront (entity targ) +{ + return infront_of_ent(targ,self); +} + + +//============================================================================ + +/* +=========== +ChangeYaw + +Turns towards self.ideal_yaw at self.yaw_speed +Sets the global variable current_yaw +Called every 0.1 sec by monsters +============ +*/ +/* + +void ChangeYaw () +{ +float ideal, move; + +//current_yaw = self.ideal_yaw; +// mod down the current angle + current_yaw = anglemod( self.angles_y ); + ideal = self.ideal_yaw; + + + if (current_yaw == ideal) + return; + + move = ideal - current_yaw; + if (ideal > current_yaw) + { + if (move > 180) + move = move - 360; + } + else + { + if (move < -180) + move = move + 360; + } + + if (move > 0) + { + if (move > self.yaw_speed) + move = self.yaw_speed; + } + else + { + if (move < 0-self.yaw_speed ) + move = 0-self.yaw_speed; + } + + current_yaw = anglemod (current_yaw + move); + + self.angles_y = current_yaw; +} + +*/ + + +//============================================================================ + +void() HuntTarget = +{ + self.goalentity = self.enemy; + if(self.spawnflags&PLAY_DEAD) + { +// dprint("getting up!!!\n"); + self.think=self.th_possum_up; + self.spawnflags(-)PLAY_DEAD; + } + else + self.think = self.th_run; +// self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + thinktime self : 0.1; +// SUB_AttackFinished (1); // wait a while before first attack +}; + +void SightSound (void) +{ + if (self.classname == "monster_archer") + sound (self, CHAN_VOICE, "archer/sight.wav", 1, ATTN_NORM); + else if (self.classname == "monster_archer_lord") + sound (self, CHAN_VOICE, "archer/sight2.wav", 1, ATTN_NORM); + else if (self.classname == "monster_mummy") + sound (self, CHAN_WEAPON, "mummy/sight.wav", 1, ATTN_NORM); + else if (self.classname == "monster_mummy_lord") + sound (self, CHAN_WEAPON, "mummy/sight2.wav", 1, ATTN_NORM); + +} + +void() FoundTarget = +{ + if (self.enemy.classname == "player") + { // let other monsters see this monster for a while + sight_entity = self; + sight_entity_time = time + 1; + } + + self.show_hostile = time + 1; // wake up other monsters + + SightSound (); + + HuntTarget (); +}; + +/* +=========== +FindTarget + +Self is currently not attacking anything, so try to find a target + +Returns TRUE if an enemy was sighted + +When a player fires a missile, the point of impact becomes a fakeplayer so +that monsters that see the impact will respond as if they had seen the +player. + +To avoid spending too much time, only a single client (or fakeclient) is +checked each frame. This means multi player games will have slightly +slower noticing monsters. +============ +*/ +float(float dont_hunt) FindTarget = +{ +entity client; +float r; + +// if the first spawnflag bit is set, the monster will only wake up on +// really seeing the player, not another monster getting angry + +// spawnflags & 3 is a big hack, because zombie crucified used the first +// spawn flag prior to the ambush flag, and I forgot about it, so the second +// spawn flag works as well + if(!deathmatch&&(self.classname=="monster_imp_lord"||self.classname=="cube_of_force")) + return FindMonsterTarget(); + + if (sight_entity_time >= time) + { + client = sight_entity; + if (client.enemy == self.enemy) + return TRUE; + } + else + { + client = checkclient (); + if (!client) + return FALSE; // current check entity isn't in PVS + } + + if (client == self.enemy) + return FALSE; + + if (client.flags & FL_NOTARGET) + return FALSE; + + r = range (client); + if (r == RANGE_FAR) + return FALSE; + + if (r == RANGE_NEAR) + { + if (client.show_hostile < time && !infront (client)) + return FALSE; + } + else if (r == RANGE_MID) + { + if (!infront (client)) + return FALSE; + } + + if (!visible (client)) + return FALSE; + +// +// got one +// + self.enemy = client; + + if (self.enemy.classname != "player") + { + self.enemy = self.enemy.enemy; + if (self.enemy.classname != "player") + { + self.enemy = world; + return FALSE; + } + } + +/* if(self.spawnflags&PLAY_DEAD) + { + if(r==RANGE_MELEE) + { + if(!dont_hunt) + FoundTarget (); + return TRUE; + } + else if(!infront_of_ent(self,self.enemy)&&random()<0.1&&random()<0.1) + { + if(!dont_hunt) + FoundTarget (); + return TRUE; + } + else + { + self.enemy=world; + return FALSE; + } + } +*/ + if(!dont_hunt) + FoundTarget (); + return TRUE; +}; + +//============================================================================= + +void(float dist) ai_forward = +{ + walkmove (self.angles_y, dist, FALSE); +}; + +void(float dist) ai_back = +{ + walkmove ( (self.angles_y+180), dist, FALSE); +}; + + +/* +============= +ai_pain + +stagger back a bit +============= +*/ +void(float dist) ai_pain = +{ +// ai_back (dist); +float away; + + away = vectoyaw (self.origin - self.enemy.origin)+90*random(0.5,-0.5); + + walkmove (away, dist,FALSE); +}; + +/* +============= +ai_painforward + +stagger back a bit +============= +*/ +void(float dist) ai_painforward = +{ + walkmove (self.ideal_yaw, dist, FALSE); +}; + +/* +============= +ai_walk + +The monster is walking it's beat +============= +*/ +void(float dist) ai_walk = +{ + + MonsterCheckContents(); + + movedist = dist; + + // check for noticing a player + if (FindTarget (FALSE)) + return; + + if(self.classname=="monster_eidolon") + { + if (!self.path_current) + riderpath_init(); + if(!eidolon_riderpath_move(dist)) + { + if(self.think==self.th_walk) + self.think=eidolon_guarding; + } + else if(self.think==eidolon_guarding) + self.think=self.th_walk; + } + else + movetogoal (dist); +}; + + +/* +============= +ai_stand + +The monster is staying in one place for a while, with slight angle turns +============= +*/ +void() ai_stand = +{ + MonsterCheckContents(); + + if (FindTarget (FALSE)) + return; + + if(self.spawnflags&PLAY_DEAD) + return; + + if (time > self.pausetime) + { + self.th_walk (); + return; + } + +// change angle slightly +}; + +/* +============= +ai_turn + +don't move, but turn towards ideal_yaw +============= +*/ +void() ai_turn = +{ + if (FindTarget (FALSE)) + return; + + ChangeYaw (); +}; + +//============================================================================= + +/* +============= +ChooseTurn +============= +*/ +void(vector dest3) ChooseTurn = +{ + local vector dir, newdir; + + dir = self.origin - dest3; + + newdir_x = trace_plane_normal_y; + newdir_y = 0 - trace_plane_normal_x; + newdir_z = 0; + + if (dir * newdir > 0) + { + dir_x = 0 - trace_plane_normal_y; + dir_y = trace_plane_normal_x; + } + else + { + dir_x = trace_plane_normal_y; + dir_y = 0 - trace_plane_normal_x; + } + + dir_z = 0; + self.ideal_yaw = vectoyaw(dir); +}; + +/* +============ +FacingIdeal + +Within angle to launch attack? +============ +*/ +float() FacingIdeal = +{ + local float delta; + + delta = anglemod(self.angles_y - self.ideal_yaw); + if (delta > 45 && delta < 315) + return FALSE; + return TRUE; +}; + + +//============================================================================= + +float() CheckAnyAttack = +{ + if (!enemy_vis) + return FALSE; + + if(self.classname=="monster_eidolon") + if(self.goalentity==self.controller) + return FALSE; + else + return eidolon_check_attack(); + + return CheckAttack (); +}; + + +/* +============= +ai_attack_face + +Turn in place until within an angle to launch an attack +============= +*/ +void() ai_attack_face = +{ + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + if (FacingIdeal()) // Ready to go get em + { + if (self.attack_state == AS_MISSILE) + self.th_missile (); + else if (self.attack_state == AS_MELEE) + self.th_melee (); + self.attack_state = AS_STRAIGHT; + } +}; + + +/* +============= +ai_run_slide + +Strafe sideways, but stay at aproximately the same range +============= +*/ +void ai_run_slide () +{ +float ofs; + + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + if (self.lefty) + ofs = 90; + else + ofs = -90; + + if (walkmove (self.ideal_yaw + ofs, movedist, FALSE)) + return; + + self.lefty = 1 - self.lefty; + + walkmove (self.ideal_yaw - ofs, movedist, FALSE); +} + + +/* +============= +ai_run + +The monster has an enemy it is trying to kill +============= +*/ +void(float dist) ai_run = +{ + + MonsterCheckContents(); + + movedist = dist; +// see if the enemy is dead + if (!self.enemy.flags2&FL_ALIVE||(self.enemy.artifact_active&ARTFLAG_STONED&&self.classname!="monster_medusa")) + { + self.enemy = world; + // FIXME: look all around for other targets + if (self.oldenemy.health > 0) + { + self.enemy = self.oldenemy; + HuntTarget (); + } + else if(coop) + { + if(!FindTarget(TRUE)) //Look for other enemies in the area + { + if (self.pathentity) + self.th_walk (); + else + self.th_stand (); + return; + } + } + else + { + if (self.pathentity) + self.th_walk (); + else + self.th_stand (); + return; + } + } + + self.show_hostile = time + 1; // wake up other monsters + +// check knowledge of enemy + enemy_vis = visible(self.enemy); + if (enemy_vis) + { + self.search_time = time + 5; + if(self.mintel) + { + self.goalentity=self.enemy; + self.wallspot=(self.enemy.absmin+self.enemy.absmax)*0.5; + } + } + else + { + if(coop) + { + if(!FindTarget(TRUE)) + if(self.model=="models/spider.mdl") + { + if(random()<0.5) + SetNextWaypoint(); + } + else + SetNextWaypoint(); + } + if(self.mintel) + if(self.model=="models/spider.mdl") + { + if(random()<0.5) + SetNextWaypoint(); + } + else + SetNextWaypoint(); + } + + if(random()<0.5&&(!self.flags&FL_SWIM)&&(!self.flags&FL_FLY)&&(self.spawnflags&JUMP)) + CheckJump(); + +// look for other coop players + if (coop && self.search_time < time) + { + if (FindTarget (FALSE)) + return; + } + + enemy_infront = infront(self.enemy); + enemy_range = range(self.enemy); + if(self.classname!="monster_eidolon") + enemy_yaw = vectoyaw(self.goalentity.origin - self.origin); + + if ((self.attack_state == AS_MISSILE) || (self.attack_state == AS_MELEE)) // turning to attack + { + if(self.classname!="monster_eidolon") + ai_attack_face (); + return; + } + + if (CheckAnyAttack ()) + return; // beginning an attack + + if (self.attack_state == AS_SLIDING) + { + ai_run_slide (); + return; + } + +// head straight in +// if(self.netname=="spider") +// check_climb(); + if(self.classname=="monster_eidolon") + { + if(!self.path_current) + riderpath_init(); + if(!eidolon_riderpath_move(dist)) + { + if(self.think==self.th_run) + eidolon_guarding(); + } + else if(self.think==eidolon_guarding) + self.th_run(); + } + else + movetogoal (dist); // done in C code... +}; + +//FAKE FUNCTIONS +void SpiderJumpBegin() +{ +} + +float mezzo_choose_roll (entity null) +{ + return FALSE; +} + diff --git a/allplay.hc b/allplay.hc new file mode 100644 index 0000000..e2ae925 --- /dev/null +++ b/allplay.hc @@ -0,0 +1,657 @@ +/*========================================= +FUNCTIONS THAT ALL PLAYERS WILL CALL +===========================================*/ +void() bubble_bob; + +vector VelocityForDamage (float dm) +{ + local vector v; + + v = randomv('-100 -100 200', '100 100 300'); + + if (dm > -50) + v = v * 0.7; + else if (dm > -200) + v = v * 2; + else + v = v * 10; + + return v; +} + + +void ReadySolid () +{ + if(!self.headmodel) + self.headmodel="models/flesh1.mdl";//Temp until player head models are in + MakeSolidCorpse (); +} + +void StandardPain(void) +{ + if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + if (random() > 0.5) + sound (self, CHAN_VOICE, "player/asspain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/asspain2.wav", 1, ATTN_NORM); + else if (random() > 0.5) + sound (self, CHAN_VOICE, "player/palpain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/palpain2.wav", 1, ATTN_NORM); +} + +void PainSound (void) +{ + + if (self.health <= 0) + return; + + if (self.deathtype == "teledeath"||self.deathtype == "teledeath2"||self.deathtype == "teledeath3"||self.deathtype == "teledeath4") + { + sound (self, CHAN_VOICE, "player/telefrag.wav", 1, ATTN_NONE); + return; + } + + if (self.pain_finished > time) + return; + + self.pain_finished = time + 0.5; + + // FIXME: Are we doing seperate sounds for these different pains???? + if(self.model=="models/yakman.mdl") + { + sound (self, CHAN_VOICE, "eidolon/pain.wav", 1, ATTN_NORM); + return; + } + else if (self.model=="models/sheep.mdl") + sheep_sound(1); + else if (/*self.watertype == CONTENT_WATER &&*/ self.waterlevel == 3) + { + if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + sound (self, CHAN_VOICE, "player/assdrown.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/paldrown.wav", 1, ATTN_NORM); + } + else //if (self.watertype == CONTENT_SLIME) + { + StandardPain(); + } +/* else if (self.watertype == CONTENT_LAVA) + { + if(self.playerclass==CLASS_ASSASSIN) + if (random() > 0.5) + sound (self, CHAN_VOICE, "player/asspain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/asspain2.wav", 1, ATTN_NORM); + else if (random() > 0.5) + sound (self, CHAN_VOICE, "player/palpain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/palpain2.wav", 1, ATTN_NORM); + } + else + { + if(self.playerclass==CLASS_ASSASSIN) + if (random() > 0.5) + sound (self, CHAN_VOICE, "player/asspain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/asspain2.wav", 1, ATTN_NORM); + else if (random() > 0.5) + sound (self, CHAN_VOICE, "player/palpain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/palpain2.wav", 1, ATTN_NORM); + }*/ +} + +void player_pain (entity attacker,float total_damage) +{ +//FIX this = need to check if firing, else make idle frames of all +// weapons frame 0? +//if (self.weaponframe) +// return; + + if(self.playerclass==CLASS_SUCCUBUS) + { + if(self.flags&FL_SPECIAL_ABILITY2) + {//Sound &/or effect? + if(self.level>9) + { + self.greenmana+=total_damage; + self.bluemana+=total_damage; + } + else + { + if(self.level>6) + self.greenmana+=total_damage*(self.level - 2/10); + self.bluemana+=total_damage*(self.level/10); + } + if(self.bluemana>self.max_mana) + self.bluemana=self.max_mana; + if(self.greenmana>self.max_mana) + self.greenmana=self.max_mana; + } + } + else if(self.playerclass==CLASS_DWARF) + if(self.super_damage_timeself.health) + {//if hit while at @30% health & not berzerked in last minute, chance to berzerk + self.super_damage=4; + self.super_damage_time=time+30; + self.colormap=140; + centerprint(self,"You are in a Berzerker Rage!!!\n"); + } + + + + self.climbing=FALSE; + self.climbspot='0 0 0'; + self.last_climb=time; + + if (self.last_attack + 0.5 > time || self.button0) + return; + + PainSound(); + +// self.weaponframe=0;//Why? + + if (self.hull==HULL_PLAYER||self.playerclass==CLASS_DWARF) + self.act_state=ACT_PAIN; + else + self.act_state=ACT_CROUCH_MOVE;//No pain animation for crouch- maybe jump? + //Make it make you stand up? +} + +void DeathBubblesSpawn () +{ +entity bubble; +vector offset; + + offset_x = random(18,-18); + offset_y = random(18,-18); + + if (pointcontents(self.owner.origin+self.owner.view_ofs)!=CONTENT_WATER) + { + remove(self); + return; + } + + bubble = spawn_temp(); + setmodel (bubble, "models/s_bubble.spr"); + setorigin (bubble, self.owner.origin+self.owner.view_ofs+offset); + bubble.movetype = MOVETYPE_NOCLIP; + bubble.solid = SOLID_NOT; + bubble.velocity = '0 0 17'; + thinktime bubble : 0.5; + bubble.think = bubble_bob; + bubble.classname = "bubble"; + bubble.frame = 0; + bubble.cnt = 0; + bubble.abslight=0.5; + bubble.drawflags(+)DRF_TRANSLUCENT|MLS_ABSLIGHT; + setsize (bubble, '-8 -8 -8', '8 8 8'); + thinktime self : 0.1; + self.think = DeathBubblesSpawn; + self.air_finished = self.air_finished + 1; + if (self.air_finished >= self.bubble_count) + remove(self); +} + +void DeathBubbles (float num_bubbles) +{ +entity bubble_owner; + +// if(self.classname=="contents damager") +// bubble_owner = self.enemy; +// else + bubble_owner = self; + + starteffect(CE_DEATHBUBBLES, bubble_owner, bubble_owner.view_ofs, num_bubbles); + +} + + +void DeathSound () +{ +// water death sounds + if (self.waterlevel == 3) + { + DeathBubbles(20); + if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + sound (self, CHAN_VOICE, "player/assdieh2.wav", 1, ATTN_NONE); + else + sound (self, CHAN_VOICE, "player/paldieh2.wav", 1, ATTN_NONE); + return; + } + else + { + if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + if (random() > 0.5) + sound (self, CHAN_VOICE, "player/assdie1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/assdie2.wav", 1, ATTN_NORM); + else if (random() > 0.5) + sound (self, CHAN_VOICE, "player/paldie1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/paldie2.wav", 1, ATTN_NORM); + } + return; +} + +void PlayerDead () +{ + self.nextthink = -1; +// allow respawn after a certain time + self.deadflag = DEAD_DEAD; + + if(self.model!=self.headmodel) + { + self.angles_x=self.angles_z=0; + pitch_roll_for_slope('0 0 0'); + } +} + +void ThrowGib (string gibname, float dm) +{ +entity new; + + new = spawn_temp(); + new.origin = (self.absmin+self.absmax)*0.5; + setmodel (new, gibname); + setsize (new, '0 0 0', '0 0 0'); + new.velocity = VelocityForDamage (dm); + new.movetype = MOVETYPE_BOUNCE; + new.solid = SOLID_NOT; + new.avelocity_x = random(600); + new.avelocity_y = random(600); + new.avelocity_z = random(600); + new.think = SUB_Remove; + new.ltime = time; + thinktime new : random(20,10); + new.scale=random(.5,.9); + new.frame = 0; + new.flags = 0; +} + +void ThrowHead (string gibname, float dm) +{ +vector org; + if(self.decap==2) + {//Brains! + if(self.movedir=='0 0 0') + { + self.movedir=normalize(self.origin+self.view_ofs-self.enemy.origin+self.enemy.proj_ofs); + self.movedir_z=0; + } + traceline(self.origin + self.view_ofs, self.origin+self.view_ofs+self.movedir*100, FALSE, self); + if (trace_fraction < 1&&!trace_ent.flags2&FL_ALIVE&&trace_ent.solid==SOLID_BSP) + { + self.wallspot=trace_endpos; + ZeBrains(trace_endpos, trace_plane_normal, random(1.3,2), rint(random(1)),0); + } + else + self.wallspot='0 0 0'; + } + + setmodel (self, gibname); + self.frame = 0; + self.takedamage = DAMAGE_NO; + if(self.classname!="player") + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_BOUNCE; + + self.mass = 1; + self.view_ofs = '0 0 8'; + self.proj_ofs='0 0 2'; + self.hull=HULL_POINT; + org=self.origin; + org_z=self.absmax_z - 4; + setsize (self, '-4 -4 -4', '4 4 4'); + setorigin(self,org); + self.flags(-)FL_ONGROUND; + self.avelocity = randomv('0 -600 0', '0 600 0'); + + if(self.decap==2) + self.velocity = VelocityForDamage (dm)+'0 0 50'; + else + self.velocity = VelocityForDamage (dm)+'0 0 200'; + + if(self.decap==2||(self.decap==1&&vlen(self.velocity)>300)) + { + if(self.wallspot=='0 0 0') + self.wallspot=org; +// self.pausetime=time+5;//watch splat or body + } + + self.think=PlayerDead; + thinktime self : 1; +} + + +void PlayerUnCrouching () +{ + tracearea (self.origin,self.origin+'0 0 28','-16 -16 0','16 16 28',FALSE,self); + if (trace_fraction < 1) + { + centerprint(self,"No room to stand up here!\n"); + self.crouch_stuck = 1; + return; + } + + setsize (self, '-16 -16 0', '16 16 56'); + self.hull=HULL_PLAYER; + if (self.viewentity.classname=="chasecam") + self.view_ofs = '0 0 0'; + + PlayerSpeed_Calc(self); + self.crouch_time = time; + + if (self.velocity_x || self.velocity_y) + self.act_state=ACT_RUN; + else + self.act_state=ACT_STAND; +} + +void PlayerCrouching () +{ + if (self.health <= 0) + return; + + setsize (self,'-16 -16 0','16 16 28'); + self.hull=HULL_CROUCH; + if (self.viewentity.classname=="chasecam") + self.view_ofs = '0 0 0'; + self.absorb_time=time + 0.3; + + PlayerSpeed_Calc(self); + self.crouch_time = time; + + self.crouch_stuck = 0; + + self.act_state=ACT_CROUCH_MOVE; +} + +void PlayerCrouch () +{ + if(self.playerclass==CLASS_DWARF) + return; + + if (self.hull==HULL_PLAYER) + PlayerCrouching(); + else if (self.hull==HULL_CROUCH) + PlayerUnCrouching(); +} + + +void GibPlayer (vector dir) +{ + vector curAngs; + + self.deadflag = DEAD_DEAD; + + curAngs = vectoangles(dir); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_PLAYER_DEATH); + //WriteEntity (MSG_MULTICAST, self); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + +// make the dir stuff work + WriteByte (MSG_MULTICAST, curAngs_y * 256.0 / 360.0); + WriteByte (MSG_MULTICAST, curAngs_x * 256.0 / 360.0); + if(self.health < -80) + { + WriteByte (MSG_MULTICAST, 300); + } + else + { + WriteByte (MSG_MULTICAST, 140); + } + + if (self.deathtype == "teledeath"||self.deathtype == "teledeath2"||self.deathtype == "teledeath3"||self.deathtype == "teledeath4") + { + WriteByte (MSG_MULTICAST, 2); + } + else if(self.health<-80) + { + WriteByte (MSG_MULTICAST, 0); + } + else + { + WriteByte (MSG_MULTICAST, 1); + } + + multicast(self.origin,MULTICAST_PHS_R); + + ThrowHead (self.headmodel, self.health); + +} + +void DecapPlayer () +{ +entity headless; + headless=spawn(); + headless.classname="headless"; + headless.decap=TRUE; + headless.movetype=MOVETYPE_STEP; + headless.solid=SOLID_PHASE; + headless.frame=50; + headless.skin=self.skin; +//Took this out so you can't fall "into" it... +// headless.owner=self; + headless.thingtype=self.thingtype; + headless.angles_y=self.angles_y; + + setmodel(headless,self.model); + setsize(headless,'-16 -16 0','16 16 36'); + setorigin(headless,self.origin); + + headless.playerclass=self.playerclass; + headless.think=self.th_goredeath; + thinktime headless : 0; + + self.health=self.health*4; + if(self.health>-30) + self.health=-30; + if(self.decap==2) + { + ThrowHead ("models/flesh1.mdl", self.health); + SpawnPuff(self.origin+self.view_ofs,'0 0 0',fabs(self.health),self); + } + else + ThrowHead (self.headmodel, self.health); + ThrowGib ("models/flesh1.mdl", self.health); + ThrowGib ("models/flesh2.mdl", self.health); + ThrowGib ("models/flesh3.mdl", self.health); + + self.deadflag = DEAD_DEAD; + if (random() < 0.5) + sound(self,CHAN_VOICE,"player/decap.wav",1,ATTN_NORM); + else if (random() < 0.5) + sound (self, CHAN_VOICE, "player/gib1.wav", 1, ATTN_NONE); + else + sound (self, CHAN_VOICE, "player/gib2.wav", 1, ATTN_NONE); +} + +void PlayerDie (float damage, vector dir) +{ + stuffcmd(self,"fov 90\n"); + stopSound(self,0); + if(self.viewentity!=self) + { + if(self.viewentity.classname=="chasecam") + remove(self.viewentity); + self.viewentity=self; + CameraViewPort(self,self); + CameraViewAngles(self,self); + } + + msg_entity=self; + WriteByte(MSG_ONE, SVC_CLEAR_VIEW_FLAGS); + WriteByte(MSG_ONE,255); + + self.artifact_low = + self.artifact_active = + self.invisible_time = + self.effects= + self.colormap=0; + + if (deathmatch || coop) + DropBackpack(); + + if(self.model=="models/sheep.mdl") + self.headmodel=""; + + self.weaponmodel=""; + self.deadflag = DEAD_DYING; + self.solid = SOLID_NOT; + self.flags(-)FL_ONGROUND; + self.movetype = MOVETYPE_TOSS; + self.attack_finished=self.teleport_time=self.pausetime=time; + self.drawflags=self.effects=FALSE; + if (self.velocity_z < 10) + self.velocity_z += random(300); + + self.artifact_active = 0; + self.rings_active =0; + + if (self.deathtype == "teledeath"||self.deathtype == "teledeath2"||self.deathtype == "teledeath3"||self.deathtype == "teledeath4") + { + self.decap=0; + self.health=-99; + } + + if(self.deathtype=="ice shatter"||self.deathtype=="stone crumble") + { + shatter(); + ThrowHead(self.headmodel,self.health); + if(self.health<-99) + self.health=-99; + return; + } + else if(self.decap) + { + DecapPlayer(); + if(self.health<-99) + self.health=-99; + return; + } + else if(self.health < -40||self.model=="models/sheep.mdl"||damage > 50)//self.modelindex==modelindex_sheep) + { + GibPlayer (dir + '0 0 1'); + if(self.health<-99) + self.health=-99; + return; + } + + DeathSound(); + + self.angles_x = 0; + self.angles_z = 0; + + if(self.bloodloss==666) + DecapPlayer(); + else + { + self.act_state=ACT_DEAD; + player_frames(); + } + if(self.health<-99) + self.health=-99; +} + +void set_suicide_frame () +{ // used by klill command and diconnect command + if (self.model != self.init_model) + return; // already gibbed +//have a self.deathframe value? Or just if-thens +// self.frame = $deatha11; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_TOSS; + self.deadflag = DEAD_DEAD; + self.nextthink = -1; +} + +void Head () +{ + ThrowSolidHead(0); +} + +void Corpse () +{ + MakeSolidCorpse(); +} + +void SolidPlayer () +{ +entity corpse; + corpse = spawn(); + if(self.angles_x>15||self.angles_x<-15) + self.angles_x=0; + if(self.angles_z>15||self.angles_z<-15) + self.angles_z=0; + corpse.angles = self.angles; + setmodel(corpse,self.model); + corpse.frame = self.frame; + corpse.colormap = self.colormap; + corpse.movetype = self.movetype; + corpse.velocity = self.velocity; + corpse.flags = 0; + corpse.effects = 0; + corpse.skin = self.skin; + corpse.controller = self; + corpse.thingtype=self.thingtype; + setorigin (corpse, self.origin); + if(self.model==self.headmodel) + { + //self.classname= + corpse.classname="head";//So they don't get mixed up with players + corpse.think=Head; + } + else + { + //self.classname= + corpse.classname="corpse";//So they don't get mixed up with players + corpse.think=Corpse; + } + thinktime corpse : 0; +} + +void player_behead () +{ + self.frame=self.level+self.cnt; + makevectors(self.angles); + if(!self.cnt) + MeatChunks (self.origin + '0 0 50',v_up*200, 3,self); + else if (self.cnt==1) + { + SpawnPuff (self.origin+v_forward*8, '0 0 48', 30,self); + sound (self, CHAN_AUTO, "misc/decomp.wav", 1, ATTN_NORM); + } + else if (self.cnt==3) + { + SpawnPuff (self.origin+v_forward*16, '0 0 36'+v_forward*16, 20,self); + sound (self, CHAN_AUTO, "misc/decomp.wav", 1, ATTN_NORM); + } + else if (self.cnt==5) + { + SpawnPuff (self.origin+v_forward*28, '0 0 20'+v_forward*32, 15,self); + sound (self, CHAN_AUTO, "misc/decomp.wav", 0.8, ATTN_NORM); + } + else if (self.cnt==8) + { + SpawnPuff (self.origin+v_forward*40, '0 0 10'+v_forward*40, 10,self); + sound (self, CHAN_AUTO, "misc/decomp.wav", 0.6, ATTN_NORM); + } + if (self.frame==self.dmg) + { + SpawnPuff (self.origin+v_forward*56, '0 0 -5'+v_forward*40, 5,self); + sound (self, CHAN_AUTO, "misc/decomp.wav", 0.4, ATTN_NORM); + ReadySolid(); + } + else + { + self.think=player_behead; + thinktime self : 0.1; + } + self.cnt+=1; +} diff --git a/altdeath.hc b/altdeath.hc new file mode 100644 index 0000000..c61df27 --- /dev/null +++ b/altdeath.hc @@ -0,0 +1,185 @@ +void ice_melt (void) +{ + self.scale -= 0.05; + if (self.scale<=0.05) + remove(self); + else + self.think=ice_melt; + thinktime self : 0.05; +} + +void ice_think (void) +{ + if(self.velocity=='0 0 0') + { + self.touch=SUB_Null; + self.think=ice_melt; + thinktime self : 1.5; + } + else + { + self.think=ice_think; + thinktime self : 0.1; + } +} + +void ice_hit (void) +{ + if (random()<0.2) + { + particleexplosion(self.origin,14,20,5); + remove(self); + } +} + +void todust (void) +{ + particleexplosion(self.origin,self.aflag,20,5); + remove(self); +} + +void pebble_hit (void) +{ + self.wait=self.wait + 1; + sound(self,CHAN_BODY,"misc/rubble.wav",1,ATTN_NORM); + if(self.wait>=3||random()<0.1) + todust(); + else + { + self.think=todust; + thinktime self : 2; + } +} +/* +void ash_hit (void) +{ + sound(self,CHAN_BODY,"misc/rubble.wav",1,ATTN_NORM); + self.wait=self.wait + 1; + if(self.wait>=3||random()<0.2) + todust(); + else + { + self.think=todust; + thinktime self : 1; + } + +} +*/ +void throw_shard (vector org,vector dir,vector spin,string type,vector ownersize) +{ +float chunk_size; + newmis=spawn_temp(); + newmis.movetype=MOVETYPE_BOUNCE; + newmis.solid=SOLID_TRIGGER; + newmis.velocity=dir; + newmis.avelocity=spin; + chunk_size=(ownersize_x+ownersize_y+ownersize_z)/3; + newmis.scale=random(0.5)*chunk_size/24; + if(!newmis.scale) + newmis.scale=0.3; + newmis.classname="type"; + setmodel(newmis,"models/shard.mdl"); + if(type=="ice") + { + newmis.skin=0; + newmis.frame=0; + newmis.touch=ice_hit; + newmis.think=ice_think; + thinktime newmis : 1; + newmis.drawflags(+)DRF_TRANSLUCENT|MLS_ABSLIGHT; + newmis.abslight=0.75; + } + else if(type=="pebbles") + { + newmis.skin=1; + newmis.frame=rint(random(1,2)); + newmis.touch=pebble_hit; + newmis.speed=16; + newmis.aflag=10; + } +/* else if(type=="ashes") + { + newmis.skin=2; + newmis.frame=rint(random(1,2)); + newmis.touch=ash_hit; + newmis.speed=1; + newmis.aflag=10; + } +*/ setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,org); +} + +void shatter () +{ +vector dir,spin,org; +float numshards,maxshards,rng; +string type; + if(self.movechain!=world&&!self.movechain.flags&FL_CLIENT) + remove(self.movechain); + if(self.scale==0) + self.scale=1; + if(self.classname=="snowball") + maxshards=random(4,2); + else + maxshards=random(7,10); + org=(self.absmin+self.absmax)*0.5; + if(self.deathtype=="ice shatter"||self.deathtype=="ice melt") + { +//origin color radius count + particleexplosion(org,14,25,50); +// particle2(org,'-50 -50 -50','50 50 50',145,14,50); + if(self.deathtype=="ice shatter") + rng=600; + else + rng=self.size_x/2; + type="ice"; + } + else if(self.deathtype=="stone crumble") + { + sound(self,CHAN_BODY,"misc/sshatter.wav",1,ATTN_NORM); + particleexplosion(org,10,60,50); +// particle2(org,'-30 -30 -30','30 30 30',16,10,50); + rng=450; + type="pebbles"; + } +/* else if(self.deathtype=="burnt crumble") + { + sound(self,CHAN_BODY,"misc/bshatter.wav",1,ATTN_NORM); + particleexplosion(org,1,60,50); +// particle2(org,'-30 -30 -30','30 30 30',1,10,50); + rng=200; + type="ashes"; + } +*/ + if(type == "ice") + { + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_ICEHIT); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, 2); // type of icehit -> shatter type + multicast(self.origin,MULTICAST_PHS_R); + } + else + { + // do stone junk + while(numshards= THINGTYPE_WEBS) + traceline(trace_endpos, spot2, FALSE, trace_ent); + + if (trace_ent != self.enemy) + { + if ((trace_ent.thingtype!=THINGTYPE_GLASS) || !trace_ent.takedamage || + (trace_ent.flags & FL_MONSTER && trace_ent.classname!="player_sheep")) + { + return FALSE; + } + } + return TRUE; +} + +void archer_duck () [++ $duck1..$duck14] +{ + ai_face(); + if(cycle_wrapped) + { + setsize(self,'-16 -16 0','16 16 56'); + if(infront(self.enemy)) + self.think=archermissile; + else + self.think=archerdrawhold; + thinktime self : 0; + return; + } + else if (self.frame==$duck1) + if (self.classname == "monster_archer") + sound (self, CHAN_VOICE, "archer/growl.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "archer/pain2.wav", 1, ATTN_NORM); + else if (self.frame == $duck5) + setsize(self,'-16 -16 0','16 16 28'); + else if (self.frame==$duck7) + { + archer_check_defense(); + thinktime self :0.2; + } +} + +void archer_check_defense() +{ + entity enemy_proj; + + if(random(2)>skill/10+self.skin/2) + return; + + if (self.enemy.last_attack+0.5= $pain1) && (self.frame <= $pain16)) // Still going through pain anims + return; + + if (self.attack_state == AS_MISSILE) + return; + + // Hurt him, will he flinch or fight back? + setsize(self,'-16 -16 0','16 16 56'); + if ((self.pain_finished > time) || (random() < .5)) + { + archerredraw(); + } + else + archer_pain_anim(); +} + +void archer_launcharrow (float arrowtype,vector spot1,vector spot2) +{ + self.last_attack=time; + + makevectors(self.angles); + if (arrowtype==GREEN_ARROW) + { + sound (self, CHAN_WEAPON, "archer/arrowg.wav", 1, ATTN_NORM); + Create_Missile(self,spot1,spot2, "models/akarrow.mdl","green_arrow",0,1000,archer_arrow_touch); + } + else if (arrowtype==RED_ARROW) + { + sound (self, CHAN_WEAPON, "archer/arrowr.wav", 1, ATTN_NORM); + CreateRedFlash(spot1); + Create_Missile(self,spot1,spot2,"models/akarrow.mdl","red_arrow",1,1000,archer_arrow_touch); + } + else + { + sound (self, CHAN_WEAPON, "archer/arrowg.wav", 1, ATTN_NORM); + CreateRedFlash(spot1); + Create_Missile(self,spot1,spot2,"models/akarrow.mdl","gold_arrow",2,1000,archer_arrow_touch); + } + newmis.drawflags(+)MLS_ABSLIGHT; + newmis.abslight=0.5; + thinktime newmis : 2.5; +} +/*----------------------------------------- + archerdrawdone - drawing his bow to fire + -----------------------------------------*/ +void archerdrawdone () [-- $tranA7..$tranA1] +{ + archer_check_defense(); + + walkmove(self.angles_y,0.5,FALSE); + + if(visible(self.enemy)) + ai_face(); + + if(cycle_wrapped) + { + self.pausetime = time + random(.5,2); + self.attack_state = AS_WAIT; + + archer_run(); + } +} + +/*----------------------------------------- + archermissile - fire his arrow + -----------------------------------------*/ +void archermissile () [++ $fire1..$fire4] +{ +float enemy_range,chance,ok,tspeed; +vector spot1, spot2; + + self.attack_state = AS_MISSILE; + + if(visible(self.enemy)) + ai_face(); + else + { + self.think=self.th_run; + thinktime self : 0; + return; + } + + if (self.frame == $fire2) // FIRE!!!! + { + makevectors(self.angles); + spot1 = self.origin + v_forward*4 + v_right * 10 + v_up * 36; + if(self.classname=="monster_archer_lord") + { + tspeed=vlen(self.enemy.velocity); + if(tspeed>100) + spot2=extrapolate_pos_for_speed(spot1,1000,self.enemy,0.3); + } + + if(spot2=='0 0 0') + { + spot2 = self.enemy.origin + self.enemy.view_ofs; + traceline (spot1, spot2, FALSE, self); + + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, FALSE, trace_ent); + + if (trace_ent == self.enemy) + ok=TRUE; + else if((trace_ent.health<=25||trace_ent.thingtype>=THINGTYPE_WEBS)&&trace_ent.takedamage&&(!trace_ent.flags&FL_MONSTER||trace_ent.classname=="player_sheep")) + ok=TRUE; + } + else + ok=TRUE; + + if(ok) + { + enemy_range = range(self.enemy); + if (enemy_range < RANGE_MELEE) // Which arrow to use? + chance = 0.80; + else if (enemy_range < RANGE_NEAR) + chance = 0.50; + else if (enemy_range < RANGE_MID) + chance = 0.30; + else if (enemy_range < RANGE_FAR) + chance = 0.10; + + if (self.classname=="monster_archer") + { + if (random(1) < chance) + archer_launcharrow(RED_ARROW,spot1,spot2); + else + archer_launcharrow(GREEN_ARROW,spot1,spot2); + } + else // Archer Lord + { + if (random(1) < chance) + archer_launcharrow(GOLD_ARROW,spot1,spot2); + else + archer_launcharrow(RED_ARROW,spot1,spot2); + } + self.attack_finished = time + random(.5,1); + if(!self.skin) + chance-=0.3; + chance+=skill/10; + + // Reattack? + if (random () > chance) // Is he done? + archerdrawdone(); + } + else + { + self.attack_finished = time + random(); + stopSound(self,CHAN_WEAPON); + //sound (self, CHAN_WEAPON, "misc/null.wav", 1, ATTN_NORM); + archer_run(); + return; + } + } + if(cycle_wrapped) + { + self.frame = $draw10 ; + archerredraw(); + } + else if(visible(self.enemy)) + ai_face(); +} + + + +/*----------------------------------------- + archerredraw - redrawing his bow to fire + -----------------------------------------*/ +void archerredraw () [++ $redraw1..$redraw12] +{ + self.attack_state = AS_MISSILE; + + archer_check_defense(); + + if (self.frame == $redraw8) + sound (self, CHAN_WEAPON, "archer/draw.wav", 1, ATTN_NORM); + + if (cycle_wrapped) + archermissile(); + else if(visible(self.enemy)) + ai_face(); + else + { + self.think=self.th_run; + thinktime self : 0; + return; + } +} + +/*----------------------------------------- + archerdrawhold - waiting for right chance to attack + -----------------------------------------*/ +void archerdrawhold () +{ +float chance,startframe,endframe; + + if(visible(self.enemy)) + ai_face(); + else + { + self.think=self.th_run; + thinktime self : 0; + return; + } + + archer_check_defense(); + + startframe=$waitB1; + endframe=$waitB12; + + if (!self.spawnflags & ARCHER_STUCK) + { + if (vlen(self.enemy.origin - self.origin)<=200) + { + if(infront(self.enemy)) + if(walkmove(self.angles_y+180,3,FALSE)) + { + startframe=$backup1; + endframe=$backup8; + } + } + } + + AdvanceFrame(startframe,endframe); + + self.think=archerdrawhold; + thinktime self : 0.05; + + enemy_range = range(self.enemy); + if (enemy_range < RANGE_NEAR && random() < 0.4) + archermissile(); + else if (cycle_wrapped||random()= $tranA1) && (self.frame <= $tranA13)) + walkmove(self.angles_y+180,.28,FALSE); + + if (cycle_wrapped) // Archer has drawn the arrow + archerdrawhold(); + else if (visible(self.enemy)) + ai_face(); + else + { + self.think=self.th_run; + thinktime self : 0; + return; + } + + if ((random(1)<.10) && (self.frame == $walk1)) + { + if (self.classname == "monster_archer") + sound (self, CHAN_BODY, "archer/growl.wav", 1, ATTN_NORM); + else + { + if (random() < .70) + sound (self, CHAN_BODY, "archer/growl2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_BODY, "archer/growl3.wav", 1, ATTN_NORM); + + } + } +} + + +/*----------------------------------------- + archer_run - run towards the enemy + -----------------------------------------*/ +void archer_run(void) +{ + self.think = archer_run; + thinktime self : HX_FRAME_TIME; + + archer_check_defense(); + + if ((random(1)<.10) && (self.frame == $walk1)) + { + if (self.classname == "monster_archer") + sound (self, CHAN_VOICE, "archer/growl.wav", 1, ATTN_NORM); + else + { + if (random() < .70) + sound (self, CHAN_VOICE, "archer/growl2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "archer/growl3.wav", 1, ATTN_NORM); + } + } + + if ((self.spawnflags & ARCHER_STUCK) || (self.attack_state == AS_WAIT)) + { + AdvanceFrame($waitA1,$waitA18); + ai_run(0); + } + else + { + AdvanceFrame($walk1,$walk16); + ai_run(4); + } +} + + +/*----------------------------------------- + archer_walk - walking his beat + -----------------------------------------*/ +void archer_walk(void) [++ $patrol1..$patrol22] +{ + thinktime self : HX_FRAME_TIME + .01; // Make him move a little slower so his run will look faster + + archer_check_defense(); + + if ((random()<.05) && (self.frame == $patrol1)) + { + if (self.classname == "monster_archer") + sound (self, CHAN_VOICE, "archer/growl.wav", 1, ATTN_NORM); + else + { + if (random() < .70) + sound (self, CHAN_VOICE, "archer/growl2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "archer/growl3.wav", 1, ATTN_NORM); + } + } + + if (self.spawnflags & ARCHER_STUCK) // No moving + { + self.frame = $patrol1; // FIXME: this should be the wait animations + ai_walk(0); + } + else + ai_walk(2.3); + +} + +/*----------------------------------------- + archer_stand - standing and waiting + -----------------------------------------*/ +void archer_stand(void) [++ $waitA1..$waitA18] +{ + if (random()<0.5) + { + + archer_check_defense(); + ai_stand(); + } +} + + +/*QUAKED monster_archer (1 0.3 0) (-16 -16 0) (16 16 50) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +The Archer Knight monster +-------------------------FIELDS------------------------- +Health : 80 +Experience Pts: 25 +Favorite TV shows: Friends & Baywatch +Favorite Color: Blue +Likes: Shooting arrows into people and long walks along the beach +Dislikes: Anything having to do with Pauly Shore +-------------------------------------------------------- +*/ +void monster_archer () +{ + if (deathmatch) + { + remove(self); + return; + } + + if (!self.flags2 & FL_SUMMONED) + { + precache_archer(); + } + + CreateEntityNew(self,ENT_ARCHER,"models/archer.mdl",archer_die); + + self.th_stand = archer_stand; + self.th_walk = archer_walk; + self.th_run = archer_run; + self.th_melee = archerdraw; + self.th_missile = archerdraw; + self.th_pain = archer_pain; + self.decap = 0; + self.headmodel = "models/archerhd.mdl"; + self.mintel = 7; + self.monsterclass = CLASS_GRUNT; + self.experience_value = 25; + self.health = 80; + + self.flags (+) FL_MONSTER; + self.yaw_speed = 10; + self.view_ofs = '0 0 40'; + + walkmonster_start(); +} + +/*QUAKED monster_archer_lord (1 0.3 0) (-16 -16 0) (16 16 50) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +The Archer Lord monster +-------------------------FIELDS------------------------- +Health : 325 +Experience Pts: 200 +Favorite Cities: Madrid & Las Vegas +Favorite Flower: Orchid +What people don't know about me: I cry at sad movies +What people say when they see me: Don't shoot!! Don't shoot!! +-------------------------------------------------------- +*/ +void monster_archer_lord () +{ + if (deathmatch) + { + remove(self); + return; + } + + if (!self.flags2 & FL_SUMMONED) + { + precache_model("models/archer.mdl"); + precache_model("models/archerhd.mdl"); + + precache_model("models/gspark.spr"); + + precache_sound ("archer/arrowg.wav"); + precache_sound ("archer/arrowr.wav"); + + precache_sound ("archer/growl2.wav"); + precache_sound ("archer/growl3.wav"); + precache_sound ("archer/pain2.wav"); + precache_sound ("archer/sight2.wav"); + precache_sound ("archer/death2.wav"); + precache_sound ("archer/draw.wav"); + + } + + CreateEntityNew(self,ENT_ARCHER,"models/archer.mdl",archer_die); + + self.th_stand = archer_stand; + self.th_walk = archer_walk; + self.th_run = archer_run; + self.th_melee = archerdraw; + self.th_missile = archerdraw; + self.th_pain = archer_pain; + self.decap = 0; + self.headmodel = "models/archerhd.mdl"; + self.mintel = 7; + self.monsterclass = CLASS_HENCHMAN; + self.experience_value = 200; + self.health = 325; + self.skin = 1; + + self.flags (+) FL_MONSTER; + self.yaw_speed = 10; + self.view_ofs = '0 0 40'; + + walkmonster_start(); +} + +/* +================= +ArcherCheckAttack +================= +*/ +float ArcherCheckAttack (void) +{ + local vector spot1, spot2; + local entity targ; + local float chance; + +// if (enemy_range <= RANGE_MELEE) // Enemy is too close...attack +// { +// self.attack_state = AS_MISSILE; + self.pain_finished = 0; +// self.attack_finished = 0; +// } + + if (self.attack_finished > time) + return FALSE; + + if (!enemy_vis) + return FALSE; + + if (enemy_range == RANGE_FAR) + { + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + archer_run (); + } + return FALSE; + } + + targ = self.enemy; + + makevectors(self.angles); +// see if any entities are in the way of the shot + spot1 = self.origin + v_right * 10 + v_up * 36; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, FALSE, trace_ent); + + if (trace_ent != targ) + if((trace_ent.health>25&&trace_ent.thingtype!=THINGTYPE_GLASS)||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + { + self.attack_state = AS_STRAIGHT; + return FALSE; + } + + // Chances of attack + // 50% at MID range + // 65% at NEAR range + // 80% at MELEE range + enemy_range = range(self.enemy); + if (enemy_range == RANGE_MELEE) + chance = 0.40; + else if (enemy_range == RANGE_NEAR) + chance = 0.3; + else if (enemy_range == RANGE_MID) + chance = 0.2; + else + chance = 0; + + if ((random () < chance) && (self.attack_state != AS_MISSILE)) // Will he attack? + { + self.attack_state = AS_MISSILE; + return TRUE; + } + + if (enemy_range == RANGE_MID) + { + if (random (1) < .5) // Will he side step? + self.attack_state = AS_SLIDING; + else + self.attack_state = AS_STRAIGHT; + } + else + { + if (self.attack_state != AS_SLIDING) + self.attack_state = AS_SLIDING; + } + + return FALSE; +} + diff --git a/artifact.hc b/artifact.hc new file mode 100644 index 0000000..88b9506 --- /dev/null +++ b/artifact.hc @@ -0,0 +1,1260 @@ +/* + * $Header: /HexenWorld/Siege/artifact.hc 31 5/25/98 1:38p Mgummelt $ + */ + + + + +/* + * artifact_touch() -- Called when an artifact is being touched. + * Awards players random amounts of whatever they represent. + */ +void() SUB_regen; +void() StartItem; +void() UseInventoryItem; +void ring_touch(void); + +//getInventoryCount--returns # of items has +float getInventoryCount(entity who, float itemType) +{ + if(itemType == STR_TORCH) + { + return who.cnt_torch; + } + else if(itemType == STR_HEALTHBOOST) + { + return who.cnt_h_boost; + } + else if(itemType == STR_SUPERHEALTHBOOST) // 5 limit + { + return who.cnt_sh_boost; + } + else if(itemType == STR_MANABOOST) + { + return who.cnt_mana_boost; + } + else if(itemType == STR_TELEPORT) + { + return who.cnt_teleport; + } + else if(itemType == STR_TOME) + { + if(tomeMode == 2)//how many tomes do i really have? um er...none? + { + return 0; + } + else + { + return who.cnt_tome; + } + } + else if(itemType == STR_SUMMON) + { + return who.cnt_summon; + } + else if(itemType == STR_INVISIBILITY) + { + return who.cnt_invisibility; + } + else if(itemType == STR_GLYPH) + { + return who.cnt_glyph; + } + else if(itemType == STR_RINGFLIGHT) + { + return who.cnt_flight; + } + else if(itemType == STR_HASTE) + { + return who.cnt_haste; + } + else if(itemType == STR_BLAST) + { + return who.cnt_blast; + } + else if(itemType == STR_POLYMORPH) + { + return who.cnt_polymorph; + } + else if(itemType == STR_CUBEOFFORCE) + { + return who.cnt_cubeofforce; + } + else if(itemType == STR_INVINCIBILITY) + { + if(dmMode == DM_CAPTURE_THE_TOKEN) + { + if (who.gameFlags & GF_HAS_TOKEN)//how many icons can i pick up when there's just 1 on level? who knows? maybe i Can pick up 50; since there will only be the opportunity to pick up that 1, tho, i'll never know for sure. uh, never mind. + { + return 1;//but it's not a real invincibility... + } + else + { + return 0; + } + } + else + return who.cnt_invincibility; + } + return 0; +} + +//rommForItem--returns # of items can pick up--0 for full capacity, negative for over capacity +float roomForItem(entity who, float itemType)//F***ING S**T IS RIGHT! exotic play modes (alt tome mode, captur the icon) NEED to be handled safely by funcs that call me, cause i treat them as normal cases. so there. +{ + float slots; + slots = 0; + + if(itemType == STR_TORCH) + { + slots = 5-who.cnt_torch; + } + else if(itemType == STR_HEALTHBOOST) + { + if (who.playerclass!=CLASS_CRUSADER) + slots = 5-who.cnt_h_boost; + else + slots = 5-who.cnt_h_boost; + } + else if(itemType == STR_SUPERHEALTHBOOST) // 5 limit + { + if (deathmatch) + slots = 2-who.cnt_sh_boost; + else + slots = 5-who.cnt_sh_boost; + } + else if(itemType == STR_MANABOOST) + { + slots = 5-who.cnt_mana_boost; + } + else if(itemType == STR_TELEPORT) + { + slots = 5-who.cnt_teleport; + } + else if(itemType == STR_TOME) + { + if(tomeMode == 2)//how many tomes can i pick up here?AAAAARRRRGGGGGGGGHHHHHHH it makes me crazy just contemplating it. + { + slots = 1; + } + else + { + slots = 2-who.cnt_tome; + } + } + else if(itemType == STR_SUMMON) + { + slots = 5-who.cnt_summon; + } + else if(itemType == STR_INVISIBILITY) + { + slots = 5-who.cnt_invisibility; + } + else if(itemType == STR_GLYPH) + { + slots = 5-who.cnt_glyph; + } + else if(itemType == STR_RINGFLIGHT) + { + slots = 5-who.cnt_flight; + } + else if(itemType == STR_HASTE) + { + slots = 5-who.cnt_haste; + } + else if(itemType == STR_BLAST) + { + slots = 15-who.cnt_blast; + } + else if(itemType == STR_POLYMORPH) + { + slots = 5-who.cnt_polymorph; + } + else if(itemType == STR_CUBEOFFORCE) + { + slots = 5-who.cnt_cubeofforce; + } + else if(itemType == STR_INVINCIBILITY) + { + if(dmMode == DM_CAPTURE_THE_TOKEN) + { + if (who.gameFlags & GF_HAS_TOKEN)//how many icons can i pick up when there's just 1 on level? who knows? maybe i Can pick up 50; since there will only be the opportunity to pick up that 1, tho, i'll never know for sure. uh, never mind. + { + slots = 0; + } + else + { + slots = 1; + } + } + else + slots = 1-who.cnt_invincibility; + } + + return slots; +} + +//adjustInventoryCount--positive numba to add, neg to subtract +void adjustInventoryCount(entity who, float itemType, float numba) +{ + float realNumba,ftemp; + + ftemp = roomForItem(who,itemType); + + if (numba==0) + return;//you're trying to break this function, aren't you? + + if (numba > 0)//adding items + { + if (ftemp <= 0) + return;//no room. + if (numba > ftemp) + realNumba = ftemp;//less room than i'd like + else + realNumba = numba;//enough room + } + else + { + realNumba = numba;//check right after adjustment to make sure don't go < 0 + } + + if(itemType == STR_TORCH) + { + who.cnt_torch+=realNumba; + if (who.cnt_torch < 0) + who.cnt_torch = 0; + } + else if(itemType == STR_HEALTHBOOST) + { + who.cnt_h_boost+=realNumba; + if (who.cnt_h_boost < 0) + who.cnt_h_boost = 0; + } + else if(itemType == STR_RINGFLIGHT) + { + who.cnt_flight+=realNumba; + if (who.cnt_flight < 0) + who.cnt_flight = 0; + } + else if(itemType == STR_SUPERHEALTHBOOST) + { + who.cnt_sh_boost+=realNumba; + if (who.cnt_sh_boost < 0) + who.cnt_sh_boost = 0; + } + else if(itemType == STR_MANABOOST) + { + who.cnt_mana_boost+=realNumba; + if (who.cnt_mana_boost < 0) + who.cnt_mana_boost = 0; + } + else if(itemType == STR_TELEPORT) + { + who.cnt_teleport+=realNumba; + if (who.cnt_teleport < 0) + who.cnt_teleport = 0; + } + else if(itemType == STR_TOME) + { + if((tomeMode == 2)&&(realNumba > 0)) + { + who.poweredFlags(+)who.weapon; + } + else + { + who.cnt_tome+=realNumba; + if (who.cnt_tome < 0) + who.cnt_tome = 0; + } + } + else if(itemType == STR_SUMMON) + { + who.cnt_summon+=realNumba; + if (who.cnt_summon < 0) + who.cnt_summon = 0; + } + else if(itemType == STR_INVISIBILITY) + { + who.cnt_invisibility+=realNumba; + if (who.cnt_invisibility < 0) + who.cnt_invisibility = 0; + } + else if(itemType == STR_GLYPH) + { + who.cnt_glyph+=realNumba; + if (who.cnt_glyph < 0) + who.cnt_glyph = 0; + } + else if(itemType == STR_HASTE) + { + who.cnt_haste+=realNumba; + if (who.cnt_haste < 0) + who.cnt_haste = 0; + } + else if(itemType == STR_BLAST) + { + who.cnt_blast+=realNumba; + if (who.cnt_blast < 0) + who.cnt_blast = 0; + } + else if(itemType == STR_POLYMORPH) + { + who.cnt_polymorph+=realNumba; + if (who.cnt_polymorph < 0) + who.cnt_polymorph = 0; + } + else if(itemType == STR_CUBEOFFORCE) + { + who.cnt_cubeofforce+=realNumba; + if (who.cnt_cubeofforce < 0) + who.cnt_cubeofforce = 0; + } + else if(itemType == STR_INVINCIBILITY) + { + if(dmMode == DM_CAPTURE_THE_TOKEN) + { + if ( (!(who.gameFlags & GF_HAS_TOKEN)) && realNumba > 0 )//fresh token + { + other.gameFlags (+) GF_HAS_TOKEN; + other.effects (+) EF_BRIGHTFIELD; + } + else if ( (who.gameFlags & GF_HAS_TOKEN) && realNumba < 0 )//byby mr token + { + other.gameFlags (-) GF_HAS_TOKEN; + other.effects (-) EF_BRIGHTFIELD; + } + } + else + { + who.cnt_invincibility+=realNumba; + if (who.cnt_invincibility < 0) + who.cnt_invincibility = 0; + } + } + +} + + +float countPlayers(void) +{ + num_players; + entity lastent; + + lastent=nextent(world); + num_players=0; + while(lastent) + { + if(lastent.classname=="player") + { + num_players+=1; + + } + lastent=find(lastent,classname,"player"); + } + return num_players; +} + +void artifact_touch() +{ + float amount; + float numPlayers; + float scaleVal; + entity oldself; + float oldInv; +// string printnum; + + if(self.artifact_name == STR_TELEPORT&&self.owner!=world) + {//Thrown teleport coin opens a portal + if(other.classname=="player"&&self.owner!=other) + { + other.flags2(+)FL_TORNATO_SAFE; + oldself = spawn(); + + oldself.goalentity = SelectSpawnPoint (); + + oldself.classname = "teleportcoin"; + oldself.inactive = FALSE; + oldself.think = teleport_coin_run; + oldself.nextthink = time + .01; + oldself.spawnflags =0; + oldself.enemy = other; + + //added this for chaos device hangin-around + setorigin (oldself, other.origin); + oldself.movetype = MOVETYPE_NONE; + oldself.solid = SOLID_TRIGGER; + oldself.takedamage = DAMAGE_NO; + setsize(oldself,'-16 -16 0','16 16 56'); + remove(self); + return; + } + else if(self.flags&FL_ONGROUND) + { + oldself = spawn(); + oldself.goalentity = SelectSpawnPoint (); + + oldself.classname = "teleportcoin"; + oldself.inactive = FALSE; + oldself.think = teleport_coin_run; + oldself.nextthink = time + .01; + oldself.spawnflags =0; + + //added this for chaos device hangin-around + setorigin (oldself, self.origin); + oldself.movetype = MOVETYPE_NONE; + oldself.solid = SOLID_TRIGGER; + oldself.takedamage = DAMAGE_NO; + setsize(oldself,'-16 -16 0','16 16 56'); + remove(self); + return; + } + } + if(other.classname != "player"||other.model=="models/sheep.mdl") + { // Only players can take artifacts + return; + } + if(other.health <= 0) + { // Player is dead + return; + } + + if (self.owner == other && self.artifact_ignore_owner_time > time) + return; + + if (self.artifact_ignore_time > time) + return; + + if(self.artifact_name == STR_INVINCIBILITY&&other.siege_team!=ST_DEFENDER) + return; + + if ((dmMode == DM_CAPTURE_THE_TOKEN) && (other.gameFlags & GF_HAS_TOKEN)) + { + return; + } + + + if(self.artifact_name == STR_GLYPH) + { + if ((other.cnt_glyph + 1) > 10||other.playerclass!=CLASS_ASSASSIN) + return; + else + other.cnt_glyph += 1; + } + else if(self.artifact_name == STR_GRENADES) + { + if ((other.cnt_grenades + 15) > 45||other.playerclass!=CLASS_SUCCUBUS) + return; + else + other.cnt_grenades += 15; + } + else if(self.artifact_name == STR_ARROWS) + { + if ((other.cnt_arrows + 25) > 100||other.playerclass==CLASS_CRUSADER||other.playerclass==CLASS_DWARF) + return; + else + other.cnt_arrows += 25; + } + else if(self.artifact_name == STR_CLIMB) + { + if (other.playerclass!=CLASS_ASSASSIN||other.flags2&FL2_WALLCLIMB) + return; + other.flags2(+)FL2_WALLCLIMB; + other.artifact_active(+)ART_CLIMB; + centerprint(other,"You have the climbing boots!\n"); + sound(other, CHAN_VOICE, "items/artpkup.wav", 1, ATTN_NORM); + stuffcmd(other, "bf\n"); + self.solid = SOLID_NOT; + self.model = string_null; + thinktime self : 10; + self.think = SUB_regen; + activator = other; + SUB_UseTargets(); // Fire all targets / killtargets + return; + } + else if(self.classname == "art_sword_and_crown") + { + if(other.siege_team==ST_DEFENDER) + return; + + if(other.siege_team==ST_ATTACKER) + { + bprint(PRINT_HIGH,other.netname); + bprint(PRINT_HIGH," has captured the "); + bprint(PRINT_HIGH,self.netname); + bprint(PRINT_HIGH,"!\n"); + centerprint_all_clients("The Crown has been Siezed!!!\n",other); + centerprint(other,"You have captured the Crown!\n"); + end_siege_game (ST_DEFENDER,WP_ATTCROWN); + } + } + else + { + if (roomForItem(other,self.artifact_name)<=0) + return; + + adjustInventoryCount(other,self.artifact_name,1); + } + + if(autoItems) + { + if((self.artifact_name == STR_INVISIBILITY)|| + (self.artifact_name == STR_HASTE)|| + (self.artifact_name == STR_CUBEOFFORCE)|| + (self.artifact_name == STR_SUPERHEALTHBOOST)|| + (self.artifact_name == STR_MANABOOST)|| + ((self.artifact_name == STR_INVINCIBILITY)&&(dmMode != DM_CAPTURE_THE_TOKEN))) + { + oldself = self; + self = other; + oldInv = self.inventory; + + if(oldself.artifact_name == STR_INVISIBILITY) + { + self.inventory = INV_INVISIBILITY; + } + else if(oldself.artifact_name == STR_HASTE) + { + self.inventory = INV_HASTE; + } + else if(oldself.artifact_name == STR_CUBEOFFORCE) + { + self.inventory = INV_CUBEOFFORCE; + } + else if(oldself.artifact_name == STR_SUPERHEALTHBOOST) + { + self.inventory = INV_SUPER_HP_BOOST; + } + else if(oldself.artifact_name == STR_MANABOOST) + { + self.inventory = INV_MANA_BOOST; + } + else if(oldself.artifact_name == STR_INVINCIBILITY) + { + self.inventory = INV_INVINCIBILITY; + } + + + UseInventoryItem(); + + self.cnt_invisibility = 0; + self.cnt_haste = 0; + self.cnt_cubeofforce = 0; + self.cnt_sh_boost = 0; + self.cnt_mana_boost = 0; + self.cnt_invincibility = 0; + + self.inventory = oldInv; + self = oldself; + } + } + + if((self.artifact_name == STR_INVINCIBILITY)&&(dmMode == DM_CAPTURE_THE_TOKEN)) + { + //bcenterprint(other.netname); + //bcenterprint(" has acquired the Icon!!!\n"); + bcenterprint2(other.netname, " has acquired the Icon!!!\n"); + + //bprint(PRINT_MEDIUM, other.netname); + //bprint(PRINT_MEDIUM, " has acquired the Icon!!!\n"); + } + else if(self.artifact_name&&self.classname == "art_sword_and_crown") + { + amount = random(); + if (amount < 0.5) + { + sprinti (other, PRINT_MEDIUM, STR_YOUPOSSESS); + sprinti (other, PRINT_MEDIUM, self.artifact_name); + } + else + { + sprinti (other, PRINT_MEDIUM, STR_YOUHAVEACQUIRED); + sprinti (other, PRINT_MEDIUM, self.artifact_name); + } + + sprint (other,PRINT_MEDIUM, "\n"); + } + + if (self.artifact_respawn) + { + self.mdl = self.model; + + numPlayers = countPlayers(); + + if(patternRunner) + { + scaleVal = 1.0; + } + else + { + scaleVal = 2.0 - (numPlayers * .125); + if(scaleVal < 1) + { + scaleVal = 1; + } + } + + if(self.artifact_name==STR_INVINCIBILITY) + thinktime self : 300; + else if(self.artifact_name==STR_INVISIBILITY) + thinktime self : 90*scaleVal; + else if(self.artifact_name==STR_TORCH) + thinktime self : 10*scaleVal; + else + thinktime self : 60*scaleVal; + self.think = SUB_regen; + } + + sound(other, CHAN_VOICE, "items/artpkup.wav", 1, ATTN_NORM); + stuffcmd(other, "bf\n"); + self.solid = SOLID_NOT; +// other.items = other.items | self.items; + self.model = string_null; + + activator = other; + SUB_UseTargets(); // Fire all targets / killtargets + + if(!self.artifact_respawn) + { + remove(self); + } +} + + +void Artifact_Cheat(void) +{ + self.cnt_sh_boost = 20; + self.cnt_summon = 20; + self.cnt_glyph = 20; + self.cnt_blast = 20; + self.cnt_polymorph = 20; + self.cnt_flight = 20; + self.cnt_cubeofforce = 20; + self.cnt_invincibility = 20; + self.cnt_invisibility = 20; + self.cnt_haste = 20; + self.cnt_mana_boost = 20; + self.cnt_sh_boost = 20; + self.cnt_h_boost = 20; + self.cnt_teleport = 20; + self.cnt_tome = 20; + self.cnt_torch = 20; +} + + +/*----------------------------------------- + GenerateArtifactModel - generate the artifact + -----------------------------------------*/ +void GenerateArtifactModel(string modelname,float art_name,float respawnflag) +{ + if (respawnflag) // Should this thing respawn + self.artifact_respawn = deathmatch; + + setmodel(self, modelname); + self.artifact_name = art_name; + self.netname = "artifact"; + + if (modelname == "models/ringft.mdl") + { + self.netname = "RingofFlight"; + self.classname = "Ring_Flight"; + self.touch = ring_touch; + } + else if (modelname != "models/a_xray.mdl") + self.touch = artifact_touch; + setsize (self, '0 0 0', '0 0 0'); + + StartItem(); +} + + +/*----------------------------------------- + spawn_artifact - decide which artifact to spawn + -----------------------------------------*/ +void spawn_artifact (float artifact,float respawnflag) +{ + if (artifact == ARTIFACT_HASTE) + GenerateArtifactModel("models/a_haste.mdl",STR_HASTE,respawnflag); + else if (artifact == ARTIFACT_POLYMORPH) + GenerateArtifactModel("models/a_poly.mdl",STR_POLYMORPH,respawnflag); + else if (artifact == ARTIFACT_GLYPH) + GenerateArtifactModel("models/a_glyph.mdl",STR_GLYPH,respawnflag); + else if (artifact == ARTIFACT_GRENADES) + GenerateArtifactModel("models/w_l3_c4.mdl",STR_GRENADES,respawnflag); + else if (artifact == ARTIFACT_ARROWS) + GenerateArtifactModel("models/arrows.mdl",STR_ARROWS,respawnflag); + else if (artifact == ARTIFACT_INVISIBILITY) + GenerateArtifactModel("models/a_invis.mdl",STR_INVISIBILITY,respawnflag); + else if (artifact == ARTIFACT_INVINCIBILITY) + GenerateArtifactModel("models/a_invinc.mdl",STR_INVINCIBILITY,respawnflag); + else if (artifact == ARTIFACT_CUBEOFFORCE) + GenerateArtifactModel("models/a_cube.mdl",STR_CUBEOFFORCE,respawnflag); +// else if (artifact == ARTIFACT_SUMMON) +// GenerateArtifactModel("models/a_summon.mdl",STR_SUMMON,respawnflag); + else if (artifact == ARTIFACT_TOME) + GenerateArtifactModel("models/a_tome.mdl",STR_TOME,respawnflag); + else if (artifact == ARTIFACT_TELEPORT) + GenerateArtifactModel("models/a_telprt.mdl",STR_TELEPORT,respawnflag); + else if (artifact == ARTIFACT_MANA_BOOST) + GenerateArtifactModel("models/a_mboost.mdl",STR_MANABOOST,respawnflag); + else if (artifact == ARTIFACT_BLAST) + GenerateArtifactModel("models/a_blast.mdl",STR_BLAST,respawnflag); + else if (artifact == ARTIFACT_TORCH) + GenerateArtifactModel("models/a_torch.mdl",STR_TORCH,respawnflag); + else if (artifact == ARTIFACT_HP_BOOST) + GenerateArtifactModel("models/a_hboost.mdl",STR_HEALTHBOOST,respawnflag); + else if (artifact == ARTIFACT_SUPER_HP_BOOST) + GenerateArtifactModel("models/a_shbost.mdl",STR_SUPERHEALTHBOOST,respawnflag); + else if (artifact == ARTIFACT_CLIMB) + GenerateArtifactModel("models/a_climb.mdl",STR_CLIMB,respawnflag); +// else if (artifact == ARTIFACT_FLIGHT)//what is this artifact supposed to be?!?!?! +// GenerateArtifactModel("models/ringft.mdl",STR_FLIGHT,respawnflag); +} + + +/* +==================================================================================================== + +SUPER HP BOOST + +==================================================================================================== +*/ + +void DecrementSuperHealth() +{ + float wait_time,over,decr_health; + + if (self.health > self.max_health) + { + if (self.health<200) + { + wait_time = 2; + decr_health = 1; + } + else if (self.health<400) // Vary rate of update time + { + decr_health = 1; + over = 200 - (self.health - 200); + wait_time = over/400; + if (wait_time < .10) + wait_time = .10; + } + else // Vary the amount of the decrement + { + wait_time = .10; + over = self.health - 400; + decr_health = over * .016; + decr_health = ceil(decr_health); + if (decr_health < 2) + decr_health = 2; + } + + self.health = self.health - decr_health; + + self.healthtime = time + wait_time; + } + else // All done, get rid of it + self.artifact_flags (-) AFL_SUPERHEALTH; + +} + + +void use_super_healthboost() +{ + self.healthtime = time + .05; + + if(self.health<0) + self.health=100; + else if (self.health < 899) + self.health = self.health + 100; + else if (self.health > 999) + self.health = 999; + + self.cnt_sh_boost -= 1; + self.artifact_flags(+)AFL_SUPERHEALTH; // Show the health is in use + + if(self.flags2&FL2_POISONED) + { + self.flags2(-)FL2_POISONED; + centerprint(self,"The poison has been cleansed from your blood...\n"); + } +} + + +/*QUAKED art_SuperHBoost (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for the Super Health Boost +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_SuperHBoost() +{ + spawn_artifact(ARTIFACT_SUPER_HP_BOOST,RESPAWN); +} + + + + +/* +==================================================================================================== + +HP BOOST + +==================================================================================================== +*/ + +void use_healthboost() +{ + if(self.health >= self.max_health) + { // Already at max health + return; + } + self.cnt_h_boost -= 1; + self.health += 25; + if(self.health > self.max_health) + { + self.health = self.max_health; + } + + if(self.flags2&FL2_POISONED) + { + self.flags2(-)FL2_POISONED; + centerprint(self,"The poison has been cleansed from your blood...\n"); + } +} + + +/*QUAKED art_HealthBoost (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for the Health Boost +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_HealthBoost() +{ + spawn_artifact(ARTIFACT_HP_BOOST,RESPAWN); +} + + + + +/* +==================================================================================================== + +The TORCH + +==================================================================================================== +*/ + +/*QUAKED art_torch (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for the torch +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_torch() +{ + spawn_artifact(ARTIFACT_TORCH,RESPAWN); +} + + +void KillTorch() +{ + if(!self.artifact_active&ART_INVISIBILITY) + self.effects(-)EF_DIMLIGHT; // Turn off lights + self.artifact_flags(-)AFL_TORCH; // Turn off torch flag + if(self.model=="models/a_torch.mdl") + remove(self); + else + { + self.cnt_torch -= 1; + if (self.cnt_torch < 0) + self.cnt_torch = 0; + } +} + +void DouseTorch()//Never called?! +{ + sound (self, CHAN_BODY, "raven/douse.wav", 1, ATTN_IDLE); + self.torchtime = 0; + KillTorch(); +} + +void DimTorch() +{ + sound (self, CHAN_BODY, "raven/kiltorch.wav", 1, ATTN_IDLE); + + self.effects(-)EF_TORCHLIGHT; + if(self.classname=="player") + self.torchtime = time + 15; + else + self.torchtime = time + 3; + self.torchthink = KillTorch; +} + + +void FullTorch() +{ + sound (self, CHAN_BODY, "raven/fire1.wav", 1, ATTN_NORM); + self.effects(+)EF_TORCHLIGHT; + if(self.classname=="player") + self.torchtime = time + 45; + else + self.torchtime = time + 7; + self.torchthink = DimTorch; +} + + +/* +============ +TorchBurn + +============ +*/ +void UseTorch() +{ + if((self.effects!=EF_DIMLIGHT) && (self.effects!=EF_TORCHLIGHT)) + { + sound (self, CHAN_WEAPON, "raven/littorch.wav", 1, ATTN_NORM); + + self.effects(+)EF_DIMLIGHT; // set player to emit light + self.torchtime = time + 1; + self.torchthink = FullTorch; + self.artifact_flags (+) AFL_TORCH; // Show the torch is in use + //self.cnt_torch -= 1;// not until it goes out or is thrown + } +} + + +/*QUAKED art_blastradius (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Blast Radius +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_blastradius() +{ + spawn_artifact(ARTIFACT_BLAST,RESPAWN); +} + + + +void UseManaBoost() +{ + self.bluemana = self.max_mana; + self.greenmana = self.max_mana; + + self.cnt_mana_boost -= 1; +} + + +/*QUAKED art_manaboost (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Mana Boost +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_manaboost() +{ + spawn_artifact(ARTIFACT_MANA_BOOST,RESPAWN); +} + + +/*QUAKED art_teleport (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Teleportation +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_teleport() +{ + remove(self); + return; + spawn_artifact(ARTIFACT_TELEPORT,RESPAWN); +} + + +/*QUAKED art_tomeofpower (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Tome of Power +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_tomeofpower() +{ + spawn_artifact(ARTIFACT_TOME,RESPAWN); +} + + +/*QUAKED art_summon (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Summoning +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_summon() +{ + spawn_artifact(ARTIFACT_SUMMON,RESPAWN); +} + +/*QUAKED art_glyph (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Glyph of the Ancients +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_glyph() +{ + spawn_artifact(ARTIFACT_GLYPH,RESPAWN); +} + + +/*QUAKED ammo_arrows (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void ammo_arrows () +{ + precache_model("models/arrows.mdl"); + spawn_artifact(ARTIFACT_ARROWS,RESPAWN); +} + +/*QUAKED ammo_grenades (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void ammo_grenades () +{ + precache_model("models/w_l3_c4.mdl"); + spawn_artifact(ARTIFACT_GRENADES,RESPAWN); +} + +/*QUAKED art_haste (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Haste +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_haste() +{ + spawn_artifact(ARTIFACT_HASTE,RESPAWN); +} + + +/*QUAKED art_polymorph (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Polymorph +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_polymorph() +{ + spawn_artifact(ARTIFACT_POLYMORPH,RESPAWN); +} + +/*QUAKED art_cubeofforce (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Cube Of Force +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_cubeofforce() +{ + if(skill>2) + { + remove(self); + return; + } + spawn_artifact(ARTIFACT_CUBEOFFORCE,RESPAWN); +} + + +/*QUAKED art_invincibility (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Invincibility +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_invincibility() +{ + spawn_artifact(ARTIFACT_INVINCIBILITY,RESPAWN); +} + +/*QUAKED art_invisibility (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for Invisibility +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_invisibility() +{ + self.classname = "Ring_WaterBreathing"; + Ring_WaterBreathing(); +// spawn_artifact(ARTIFACT_INVISIBILITY,RESPAWN); +} + +/*QUAKED art_climb (.0 .0 .5) (-8 -8 -44) (8 8 20) FLOATING +Artifact for wallclimbing +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void art_climb() +{ + precache_model("models/a_climb.mdl"); + spawn_artifact(ARTIFACT_CLIMB,RESPAWN); +} + +void spawn_art_sword_and_crown(void) +{ + self.effects=EF_BRIGHTLIGHT; + setmodel(self, self.mdl); + if(!self.netname) + self.netname = "Crown"; + self.touch = artifact_touch; + setsize (self, '-8 -8 0', '8 8 8'); + + StartItem(); +} + +/*QUAKED art_sword_and_crown (.0 .0 .5) (-8 -8 0) (8 8 20) FLOATING +Artifact for Sword and Crown +-------------------------FIELDS------------------------- +"mdl" set this if you want to use your own model- this includes path and extension- for example: "models/xcalibur.mdl" +"netname" set this if you want to give your winning Siege Piece it's own name when you capture it- for example: "Excalibur" +-------------------------------------------------------- +*/ +void art_sword_and_crown() +{ + self.spawnflags(+)1; + if(!self.mdl) + self.mdl = "models/crown.mdl"; + precache_model2(self.mdl); + self.artifact_respawn = deathmatch; + spawn_art_sword_and_crown(); +} + +void item_spawner_use(void) +{ + DropBackpack(); +} + +/*QUAKED item_spawner (.0 .0 .5) (-8 -8 -44) (8 8 20) +Generic item spawner +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void item_spawner() +{ + setmodel(self, self.model); // set size and link into world + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_NONE; + self.modelindex = 0; + self.model = ""; + self.effects = EF_NODRAW; + + self.use = item_spawner_use; +} + +void tokenDrop() +{ + //bprint(PRINT_MEDIUM, "Teleporting the Icon to a new location...\n"); + bcenterprint2("","Teleporting the Icon to a new location...\n"); + remove(self); +} + +void spawnNewDmToken(entity spawnSpot, float persists) +{ + entity oldself, newGuy; + + oldself = self; + + newGuy = spawn(); + newGuy.origin = spawnSpot.origin + '0 0 40'; + self = newGuy; + + spawn_artifact(ARTIFACT_INVINCIBILITY,NO_RESPAWN); + newGuy.classname = "dmMode1_token"; + + if(!persists) + { + newGuy.nextthink = time + 10.0; + newGuy.think = tokenDrop; + newGuy.velocity_x = random(-200,200); + newGuy.velocity_y = random(-200,200); + newGuy.velocity_z = 300; + } + newGuy.effects (+) EF_BRIGHTFIELD; + + self = oldself; +} + + +float stealRandomItem(entity from, entity to) +{ + entity item; + if (item.cnt_torch) + { + spawn_artifact(ARTIFACT_TORCH,NO_RESPAWN); + } + else if (item.cnt_h_boost) + { + spawn_artifact(ARTIFACT_HP_BOOST,NO_RESPAWN); + } + else if (item.cnt_sh_boost) + { + spawn_artifact(ARTIFACT_SUPER_HP_BOOST,NO_RESPAWN); + } + else if (item.cnt_mana_boost) + { + spawn_artifact(ARTIFACT_MANA_BOOST,NO_RESPAWN); + } + else if (item.cnt_teleport) + { + spawn_artifact(ARTIFACT_TELEPORT,NO_RESPAWN); + } + else if (item.cnt_tome) + { + spawn_artifact(ARTIFACT_TOME,NO_RESPAWN); + } + else if (item.cnt_summon) + { + spawn_artifact (ARTIFACT_SUMMON,NO_RESPAWN); + } + else if (item.cnt_invisibility) + { + spawn_artifact (ARTIFACT_INVISIBILITY,NO_RESPAWN); + } + else if (item.cnt_glyph) + { + spawn_artifact (ARTIFACT_GLYPH,NO_RESPAWN); + } + else if (item.cnt_haste) + { + spawn_artifact (ARTIFACT_HASTE,NO_RESPAWN); + } + else if (item.cnt_blast) + { + spawn_artifact(ARTIFACT_BLAST,NO_RESPAWN); + } + else if (item.cnt_polymorph) + { + spawn_artifact (ARTIFACT_POLYMORPH,NO_RESPAWN); + } + else if (item.cnt_flight) + { + spawn_artifact (ARTIFACT_FLIGHT,NO_RESPAWN); + } + else if (item.cnt_cubeofforce) + { + spawn_artifact (ARTIFACT_CUBEOFFORCE,NO_RESPAWN); + } + else if (item.cnt_invincibility) + { + spawn_artifact (ARTIFACT_INVINCIBILITY,NO_RESPAWN); + } + return 3; +} + diff --git a/assassin.hc b/assassin.hc new file mode 100644 index 0000000..8a31541 --- /dev/null +++ b/assassin.hc @@ -0,0 +1,429 @@ +/* + * $Header: /HexenWorld/Siege/assassin.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\players\assassin\newfinal\assassin.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\players\assassin\newfinal +$origin 0 0 0 +$base BASE Skin +$skin Skin +$flags 0 + +// +$frame attdag1 attdag2 attdag3 attdag4 attdag5 +$frame attdag6 attdag7 attdag8 attdag9 attdag10 +$frame attdag11 + +// +$frame attstf1 attstf2 attstf3 attstf4 + +// +$frame attxbw1 attxbw2 attxbw3 attxbw4 + +// +$frame crouch1 crouch2 crouch3 crouch4 crouch5 +$frame crouch6 crouch7 crouch8 crouch9 crouch10 +$frame crouch11 crouch12 crouch13 crouch14 crouch15 +$frame crouch16 crouch17 crouch18 crouch19 crouch20 + +// +$frame death1 death2 death3 death4 death5 +$frame death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 +$frame death16 death17 death18 death19 death20 + +// +$frame decap1 decap2 decap3 decap4 decap5 +$frame decap6 decap7 decap8 decap9 decap10 +$frame decap11 decap12 decap13 decap14 decap15 +$frame decap16 decap17 decap18 decap19 decap20 +$frame decap21 decap22 decap23 decap24 decap25 +$frame decap26 decap27 decap28 + +// +$frame flydag1 flydag2 flydag3 flydag4 flydag5 +$frame flydag6 flydag7 flydag8 flydag9 flydag10 +$frame flydag11 flydag12 flydag13 flydag14 flydag15 + +// +$frame flystf1 flystf2 flystf3 flystf4 flystf5 +$frame flystf6 flystf7 flystf8 flystf9 flystf10 +$frame flystf11 flystf12 flystf13 flystf14 flystf15 + +// +$frame flyxbw1 flyxbw2 flyxbw3 flyxbw4 flyxbw5 +$frame flyxbw6 flyxbw7 flyxbw8 flyxbw9 flyxbw10 +$frame flyxbw11 flyxbw12 flyxbw13 flyxbw14 flyxbw15 + +// +$frame jump1 jump2 jump3 jump4 jump5 +$frame jump6 jump7 jump8 jump9 jump10 +$frame jump11 jump12 + +// +$frame paindag1 paindag2 paindag3 paindag4 paindag5 +$frame paindag6 paindag7 + +// +$frame painstf1 painstf2 painstf3 painstf4 painstf5 +$frame painstf6 painstf7 + +// +$frame painxbw1 painxbw2 painxbw3 painxbw4 painxbw5 +$frame painxbw6 painxbw7 + +// +$frame rundag1 rundag2 rundag3 rundag4 rundag5 +$frame rundag6 rundag7 rundag8 rundag9 rundag10 +$frame rundag11 rundag12 + +// +$frame runstf1 runstf2 runstf3 runstf4 runstf5 +$frame runstf6 runstf7 runstf8 runstf9 runstf10 +$frame runstf11 runstf12 + +// +$frame runxbw1 runxbw2 runxbw3 runxbw4 runxbw5 +$frame runxbw6 runxbw7 runxbw8 runxbw9 runxbw10 +$frame runxbw11 runxbw12 + +// +$frame stddag1 stddag2 stddag3 stddag4 stddag5 +$frame stddag6 stddag7 stddag8 stddag9 stddag10 +$frame stddag11 stddag12 stddag13 + +// +$frame stdstf1 stdstf2 stdstf3 stdstf4 stdstf5 +$frame stdstf6 stdstf7 stdstf8 stdstf9 stdstf10 +$frame stdstf11 stdstf12 stdstf13 + +// +$frame stdxbw1 stdxbw2 stdxbw3 stdxbw4 stdxbw5 +$frame stdxbw6 stdxbw7 stdxbw8 stdxbw9 stdxbw10 +$frame stdxbw11 stdxbw12 stdxbw13 + +/*-------------------------- +ACTUAL (UNIQUE TO CLASS) PLAYER CODE +----------------------------*/ +void() player_assassin_run; +void() player_assassin_crouch_stand; +void() player_assassin_crouch_move; +void() player_assassin_stand; + +float test_array [2] = +{ + 1, 2 +}; + +void() player_assassin_jump=[++ test_array[1] .. test_array[2] ] +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_assassin_swim = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel<3) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_assassin_hands_swim =[++$flydag1..$flydag15] +{ + player_assassin_swim(); +}; + +void() player_assassin_staff_swim =[++$flystf1..$flystf15] +{ + player_assassin_swim(); +}; + +void() player_assassin_xbow_swim =[++$flyxbw1..$flyxbw15] +{ + player_assassin_swim(); +}; + +void() player_assassin_fly = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype!=MOVETYPE_FLY) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_assassin_hands_fly =[++$flydag1..$flydag15] +{ + player_assassin_fly(); +}; + +void() player_assassin_staff_fly =[++$flystf1..$flystf15] +{ + player_assassin_fly(); +}; + +void() player_assassin_xbow_fly =[++$flyxbw1..$flyxbw15] +{ + player_assassin_fly(); +}; + +void() player_assassin_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_assassin_crouch_stand; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (self.velocity_x || self.velocity_y) + self.think=self.th_run; +}; + +void() player_assassin_hands_stand =[++$stddag1..$stddag13] +{ + player_assassin_stand(); +}; + +void() player_assassin_staff_stand =[++$stdstf1..$stdstf13] +{ + player_assassin_stand(); +}; + +void() player_assassin_xbow_stand =[++$stdxbw1..$stdxbw13] +{ + player_assassin_stand(); +}; + +void() player_assassin_run = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_assassin_crouch_move; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; +}; + +void() player_assassin_hands_run =[++$rundag1..$rundag12] +{ + player_assassin_run(); +}; + +void() player_assassin_staff_run =[++$runstf1..$runstf12] +{ + player_assassin_run(); +}; + +void() player_assassin_xbow_run =[++$runxbw1..$runxbw12] +{ + player_assassin_run(); +}; + +void() player_assassin_crouch_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.frame>$crouch20 || self.frame<$crouch1) + self.frame=$crouch1; + if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_stand; + else if (self.velocity_x || self.velocity_y) + self.think=player_assassin_crouch_move; + thinktime self : HX_FRAME_TIME; +}; + +void() player_assassin_crouch_move =[++$crouch1..$crouch20] +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.movetype==MOVETYPE_FLY) + self.think=player_assassin_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_run; + else if (!self.velocity_x && !self.velocity_y) + self.think=player_assassin_crouch_stand; +}; + +void() player_assassin_attack= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped&&!self.button0) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_assassin_hands_attack=[++$attdag1..$attdag11] +{ + player_assassin_attack(); +}; + +void() player_assassin_xbow_attack=[++$attxbw1..$attxbw4] +{ + player_assassin_attack(); +}; + +void() player_assassin_staff_attack=[++$attstf1..$attstf4] +{ + player_assassin_attack(); +}; + +void() player_assassin_pain= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_assassin_hands_pain =[++$paindag1..$paindag7] +{ + if(self.frame==$paindag1) + PainSound(); + player_assassin_pain(); +}; + +void() player_assassin_staff_pain =[++$painstf1..$painstf7] +{ + if(self.frame==$painstf1) + PainSound(); + player_assassin_pain(); +}; + +void() player_assassin_xbow_pain =[++$painxbw1..$painxbw7] +{ + if(self.frame==$painxbw1) + PainSound(); + player_assassin_pain(); +}; + +void() player_assassin_die1=[++$death1..$death20] +{ + if(cycle_wrapped) + { + self.frame=$death20; + self.think=PlayerDead; + } +}; + +void() player_assassin_die2=[++$death1..$death20] +{ + if(cycle_wrapped) + { + self.frame=$death20; + self.think=PlayerDead; + } +}; + +void() player_assassin_behead = +{ + self.level=$decap1; + self.dmg=$decap28; + self.cnt=0; + player_behead(); +}; + +void Ass_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1||self.weapon==IT_WEAPON3) + { + self.th_stand=player_assassin_hands_stand; + if(self.weapon==IT_WEAPON3) + self.th_missile=grenade_throw; + else + self.th_missile=Ass_Pdgr_Fire; + self.th_run=player_assassin_hands_run; + self.th_pain=player_assassin_hands_pain; + self.th_swim=player_assassin_hands_swim; + self.th_fly=player_assassin_hands_fly; + } + else if(self.weapon==IT_WEAPON4) + { + self.th_stand=player_assassin_staff_stand; + self.th_missile=ass_setstaff_fire; + self.th_run=player_assassin_staff_run; + self.th_pain=player_assassin_staff_pain; + self.th_swim=player_assassin_staff_swim; + self.th_fly=player_assassin_staff_fly; + } + else + { + self.th_stand=player_assassin_xbow_stand; + self.th_missile=crossbow_fire; + self.th_run=player_assassin_xbow_run; + self.th_pain=player_assassin_xbow_pain; + self.th_swim=player_assassin_xbow_swim; + self.th_fly=player_assassin_xbow_fly; + } + if(self.hull!=HULL_CROUCH) + self.think=self.th_stand; +} + +/* +void assassin_spurt () +{ + makevectors(self.angles); + SpawnPuff (self.origin+'0 0 56'+v_forward*12, '0 0 35',5,self); + thinktime self : 1; +} + +void assassin_hurt(void) +{ + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.takedamage=DAMAGE_YES; + self.flags2(+)FL_ALIVE; + self.thingtype=THINGTYPE_FLESH; + self.frame=$painstf4; + self.colormap=187; + setmodel (self, "models/assassin.mdl"); + + setsize (self, '-16 -16 0', '16 16 200'); + self.hull=HULL_POINT; + self.health = self.max_health=2000; + self.mass = 2000; + self.drawflags(+)MLS_ABSLIGHT; + self.abslight=0.5; +} +*/ + diff --git a/assgren.hc b/assgren.hc new file mode 100644 index 0000000..1dc4524 --- /dev/null +++ b/assgren.hc @@ -0,0 +1,294 @@ +/* + * $Header: /HexenWorld/Siege/assgren.hc 16 5/25/98 1:38p Mgummelt $ +* Grenade Throw, Assassin. +*/ + +/* +============================================================================== + +Q:\art\models\weapons\grenades\final\assgr.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\grenades\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +$frame select1 select2 select3 select4 select5 +$frame select6 + +$frame idle + +$frame throw1 throw2 throw3 throw4 throw5 +$frame throw6 throw7 throw8 throw9 throw10 +$frame throw11 throw12 + +void grenade_trail () +{ + if(self.lifetime70) + missile.think=SuperGrenadeExplode; + else + missile.think=AssGrenExplosion; + thinktime missile : random(0.1,0.6); + missile.effects (+) EF_NODRAW; + } + self.dmg*=2; + if(self.classname=="multigrenade") + { + //testing: put back in damage!!!!!! + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_BIGGRENADE); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS_R); +// remove(self); + + if(random()<0.3) + MonsterQuake(200); + MultiExplode(); + } + else + AssGrenExplosion(); + + + +}; + +void() ThrowMultiGrenade = +{//FIXME: too many t_rad's? +entity missile; + makevectors(self.v_angle); + sound(self,CHAN_WEAPON,"misc/whoosh.wav",1,ATTN_NORM); + missile=spawn(); + missile.frags=TRUE; + missile.owner=self; + missile.classname="multigrenade"; + missile.movetype=MOVETYPE_BOUNCE; + missile.solid=SOLID_BBOX; + missile.takedamage=DAMAGE_YES; + missile.health=3; + missile.th_die=SuperGrenadeExplode; + missile.touch=GrenadeTouch2; + missile.dmg=250;//simulates max level for now + + missile.o_angle = self.origin+self.proj_ofs+v_forward*8+v_right*8; + + missile.speed=500+self.weaponframe_cnt*10; +// missile.velocity=(normalize(v_forward)+'0 0 .4')*missile.speed; +//UQ method + if(self.v_angle_x) + missile.velocity = v_forward*missile.speed + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10; + else + { + missile.velocity = aim(self, missile.o_angle,1000); + missile.velocity = missile.velocity * missile.speed; + missile.velocity_z = 200; + } + + missile.angles = vectoangles(missile.velocity); + missile.avelocity=randomv('-300 -300 -300','300 300 300'); + + setmodel(missile,"models/assgren.mdl"); + missile.scale=2; + setsize (missile, '0 0 0', '0 0 0'); + setorigin(missile,missile.o_angle); + + missile.lifetime=time+2; + missile.think=grenade_trail; + thinktime missile : 0; +}; + + + +void()grenade_select; +void()grenade_throw; +void grenade_idle(void) +{ + self.th_weapon=grenade_idle; + self.weaponframe=$idle; +} + +void grenade_reload (void) +{ + self.th_weapon=grenade_reload; + self.wfs = advanceweaponframe($select1,$select6); + self.weaponmodel = "models/v_assgr.mdl"; + if (self.wfs==WF_CYCLE_WRAPPED) + grenade_idle(); +} + +void grenade_throw (void) +{ + self.th_weapon=grenade_throw; + self.wfs = advanceweaponframe($throw1,$throw12); + if(self.button0&&self.weaponframe==$throw5) + { + self.weaponframe=$throw4; + if(self.weaponframe_cnt<50) + self.weaponframe_cnt+=1; + } + else if(self.weaponframe==$throw10) + { + if(self.artifact_active&ART_TOMEOFPOWER) + { + ThrowMultiGrenade(); + self.attack_finished=time + 2; + } + else + { + ThrowMiniGrenade(); + self.attack_finished=time+0.3; + } + self.weaponframe_cnt=0; + } + else if (self.wfs==WF_CYCLE_WRAPPED) + grenade_reload(); +} + +void grenade_select (void) +{ +//selection sound? + self.th_weapon=grenade_select; + self.wfs = advanceweaponframe($select1,$select6); + self.weaponmodel = "models/v_assgr.mdl"; + if (self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + grenade_idle(); + } +} + +void grenade_deselect (void) +{ +//selection sound? + self.th_weapon=grenade_deselect; + self.wfs = advanceweaponframe($select6,$select1); + if (self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + diff --git a/assweap.hc b/assweap.hc new file mode 100644 index 0000000..69c5eda --- /dev/null +++ b/assweap.hc @@ -0,0 +1,90 @@ + +void() SnakeHit = +{ + if(other==self.owner||(other.owner==self.owner&&other.classname=="snakearrow")) + return; + if(other.takedamage) + { + other.bloodloss=other.bloodloss+1; + SpawnPuff(other.origin,'0 0 0',self.mass,other); + T_Damage(other,self,self.owner,self.mass); + } + remove(self); +// MultiExplode(); +}; + +void() FireSnakeArrow = +{ +local entity missile; + missile=spawn(); + missile.classname="snakearrow"; + missile.movetype=MOVETYPE_FLYMISSILE; + missile.solid=SOLID_BBOX; +// missile.takedamage=DAMAGE_YES; +// missile.health=10; + if(self.classname=="player") + { + makevectors(self.v_angle); + missile.owner=self; + missile.mass=100; + missile.aflag=TRUE; + missile.o_angle=self.v_angle; + self.attack_finished=time + 0.5; + } + else + { + makevectors(self.o_angle); + missile.o_angle=self.o_angle; + } +// missile.th_die=MultiExplode; + missile.touch=SnakeHit; + + missile.velocity=normalize(v_forward)*(350+self.mass); + +// setmodel(missile,"models/laser.mdl"); + missile.skin=2; + setsize(missile,'0 0 0','0 0 0'); + if(self.classname=="snakearrow") + { + missile.owner=self.owner; + missile.mass=self.mass=self.mass*0.5; + setorigin(missile,self.origin); + if(self.aflag) + { + self.aflag=missile.aflag=FALSE; + missile.velocity=missile.velocity+v_right*30; + self.velocity=self.velocity-v_right*30; + } + else + { + self.aflag=missile.aflag=TRUE; + missile.velocity=missile.velocity+v_up*30; + self.velocity=self.velocity-v_up*30; + } + if(self.mass>10) + { + self.think=FireSnakeArrow; + self.nextthink=time + 0.15; + } + else + { + self.think=SUB_Remove; + self.nextthink=time+5; + } + } + else + setorigin(missile,self.origin+self.proj_ofs+v_forward*8); + + missile.angles=vectoangles(missile.velocity); + if(missile.mass>10) + { + missile.think=FireSnakeArrow; + missile.nextthink=time + 0.15; + } + else + { + missile.think=SUB_Remove; + missile.nextthink=time+5; + } +}; + diff --git a/axe.hc b/axe.hc new file mode 100644 index 0000000..f2b292f --- /dev/null +++ b/axe.hc @@ -0,0 +1,329 @@ +/* + * $Header: /HexenWorld/Siege/axe.hc 22 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\axe\final\axe.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\axe\final +$origin 10 -10 10 +$base BASE skin +$skin skin +$flags 0 + +$frame AxeRoot1 + +$frame 1stAxe1 1stAxe2 1stAxe3 1stAxe4 1stAxe5 +$frame 1stAxe6 1stAxe7 1stAxe8 +$frame 1stAxe11 1stAxe12 1stAxe14 +$frame 1stAxe15 1stAxe17 1stAxe18 +$frame 1stAxe21 1stAxe22 1stAxe23 +$frame 1stAxe25 1stAxe27 + + +float AXE_DAMAGE = 24; +float AXE_ADD_DAMAGE = 6; + +void() T_PhaseMissileTouch; + +void() T_PhaseMissileTouch = +{ + local float damg; + + self.flags (-) FL_ONGROUND; // So it never thinks it is touching the ground + + if (other == self.owner) + return; // don't explode on owner + + if ((self.enemy == other) && (other != world)) // Can't hit same enemy twice in a row but you can hit world twice + return; + + self.cnt +=1; +// self.velocity = self.velocity * 0.75; // client's not interested in this happening... + + self.angles = vectoangles(self.velocity); + + if (pointcontents(self.origin) == CONTENT_SKY) + { + stopSound(self,0); + + remove(self); + return; + } + + if (other.health) // Hit something that can be hurt + { + if(self.classname == "powerupaxeblade") + { + damg = random(25, 45); + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_AXE_EXPLODE); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 16); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 16); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 16); + multicast(self.origin,MULTICAST_PHS_R); + + T_RadiusDamage (self, self.owner, 30.0, other); + // get rid of it here or something? + } + else + { + damg = random(30,50); + } + T_Damage (other, self, self.owner, damg ); + self.counter -=1; + self.enemy = other; + } + else + { + self.enemy = other; + if (self.cnt <4) // Bounce three times then die + { + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_AXE_BOUNCE); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 16); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 16); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 16); + multicast(self.origin,MULTICAST_PHS_R); + } + else + self.counter = 0; + } + + // Time is up + if (self.lifetime < time) + self.counter = 0; + + if (self.counter < 1) + { + remove(self); + return; + } + self.think(); +}; + +void axeblade_gone(void) +{ + stopSound(self,0); + + if (self.skin==0) + CreateLittleWhiteFlash(self.origin); + else + CreateLittleBlueFlash(self.origin); + + remove(self); +} + +/*void axeblade_run (void) [ ++ 0 .. 5] +{ + self.angles = vectoangles(self.velocity); + if (self.lifetime < time) + axeblade_gone(); +}*/ + +void axeblade_think(void) +{ + self.movedir = normalize(self.velocity); + + self.angles = vectoangles(self.movedir); + + traceline(self.origin, self.origin + self.movedir * 330.0, TRUE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_AXE); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 100); + multicast(self.origin,MULTICAST_PVS); + + thinktime self : 0.3; + + if (self.lifetime < time) + axeblade_gone(); +} + +void launch_axe (vector dir_mod,vector angle_mod) +{ + entity missile; + + self.attack_finished = time + 0.4; + + missile = spawn (); + + CreateEntityNew(missile,ENT_AXE_BLADE,"models/axblade.mdl",SUB_Null); + + missile.owner = self; + missile.classname = "ax_blade"; + + // set missile speed + makevectors (self.v_angle + dir_mod); + missile.velocity = normalize(v_forward); + missile.movedir = missile.velocity; + + // PUT THIS BACK PLEASE + missile.velocity = missile.velocity * 1100; + + missile.touch = T_PhaseMissileTouch; + + // Point it in the proper direction + missile.angles = vectoangles(missile.velocity); + missile.angles += angle_mod; + + // set missile duration + missile.counter = 4; // Can hurt two things before disappearing + missile.cnt = 0; // Counts number of times it has hit walls + missile.lifetime = time + 2; // Or lives for 2 seconds and then dies when it hits anything + + setorigin (missile, self.origin + self.proj_ofs + v_forward*10 + v_right * 1); + + if (self.artifact_active & ART_TOMEOFPOWER) + { + missile.frags=TRUE; + missile.classname = "powerupaxeblade"; + missile.skin = 1; + missile.drawflags = (self.drawflags & MLS_MASKOUT)| MLS_POWERMODE; + } + else + missile.classname = "axeblade"; + +// thinktime missile : HX_FRAME_TIME; +// missile.think = axeblade_run; + + missile.think = axeblade_think; + thinktime missile : 0.3; + + missile.effects (+) EF_NODRAW; + + entity oldself; + oldself = self; + self = missile; + + missile.think(); + + self = oldself; +} + + +/* +================ +axeblade_fire +================ +*/ +void() axeblade_fire = +{ +float damg,damg_mod; + damg=random(7) + 5; +// damg=500; + damg_mod=melee_dmg_mod_for_strength(self.strength); + damg*=damg_mod; + if(self.playerclass==CLASS_DWARF) + FireMelee (damg,0,32); + else + FireMelee (damg,0,64); +/* if ((self.artifact_active & ART_TOMEOFPOWER) && (self.greenmana >= 8)) + { + FireMelee (50,25,64); + weapon_sound(self, "paladin/axgen.wav"); + + launch_axe('0 3 0','0 0 0'); // Side + launch_axe('0 -3 0','0 0 0'); // Side + + + self.greenmana -= 8; + } + else if (self.greenmana >= 2) + { + FireMelee (WEAPON1_BASE_DAMAGE,WEAPON1_ADD_DAMAGE,64); + + if (self.greenmana >= 2) + { + weapon_sound(self, "paladin/axgen.wav"); + + launch_axe('0 0 0','0 0 0'); + self.greenmana -= 2; + } + } +*/ + +}; + +void axe_ready (void) +{ + self.th_weapon=axe_ready; + self.weaponframe = $AxeRoot1; +} + +void axe_select (void) +{ + self.wfs = advanceweaponframe($1stAxe18,$1stAxe3); + if (self.weaponframe == $1stAxe14) + { + weapon_sound(self, "weapons/vorpswng.wav"); + } + + self.weaponmodel = "models/axe.mdl"; + self.th_weapon=axe_select; + self.last_attack=time; + + if (self.wfs == WF_LAST_FRAME) + { + self.attack_finished = time - 1; + axe_ready(); + } +} + +void axe_deselect (void) +{ + self.wfs = advanceweaponframe($1stAxe18,$1stAxe3); + self.th_weapon=axe_deselect; + self.oldweapon = IT_WEAPON2; + + if (self.wfs == WF_LAST_FRAME) + W_SetCurrentAmmo(); +} + + +void axe_a (void) +{ + + self.wfs = advanceweaponframe($1stAxe1,$1stAxe25); + self.th_weapon = axe_a; + + // These frames are used during selection animation + if ((self.weaponframe >= $1stAxe2) && (self.weaponframe <= $1stAxe4)) + self.weaponframe +=1; + else if ((self.weaponframe >= $1stAxe6) && (self.weaponframe <= $1stAxe7)) + self.weaponframe +=1; + + if (self.weaponframe == $1stAxe15) + { + //sound (self, CHAN_WEAPON, "weapons/vorpswng.wav", 1, ATTN_NORM); + weapon_sound(self, "weapons/vorpswng.wav"); + axeblade_fire(); + } + + if (self.wfs == WF_LAST_FRAME) + axe_ready(); +} + +void pal_axe_fire(void) +{ + axe_a (); + + if (self.artifact_active & ART_TOMEOFPOWER) + self.attack_finished = time + .7; + else if(self.playerclass==CLASS_DWARF) + self.attack_finished = time + 0.1;//time+rate_and_acc_for_weap[(self.playerclass - 1)*6+(self.weapon - 1)*2]; + else + self.attack_finished = time + 0.2;//time+rate_and_acc_for_weap[(self.playerclass - 1)*6+(self.weapon - 1)*2]; +} + diff --git a/barrel.hc b/barrel.hc new file mode 100644 index 0000000..e5dd6bf --- /dev/null +++ b/barrel.hc @@ -0,0 +1,886 @@ +/* + * $Header: /HexenWorld/Siege/barrel.hc 11 5/31/98 2:58p Mgummelt $ + */ +/* +============================================================================== + +BARRELS + +============================================================================== +*/ + + + +$cd \art\models\objects\barrel\final +$base base 128 128 +$skin skin +$frame resting + +//Checks to see if the bounding boxes of the 2 ents overlap at any point. +//Not intended for BSP models- bounding box models only +float overlapped (entity ent1, entity ent2) +{ +vector mins1,maxs1,mins2,maxs2; +float overlapped_axes; + + mins1=ent1.absmin; + maxs1=ent1.absmax; + mins2=ent2.absmin; + maxs2=ent2.absmax; + + if(mins1_x>maxs2_x||maxs1_xmaxs2_y||maxs1_ymaxs2_z||maxs1_zCHUNK_MAX) + model_cnt=CHUNK_MAX; + + while (model_cnt>0) + { + if (chunk_cnt < CHUNK_MAX*2) + { + CreateModelChunks(space,scalemod); + chunk_cnt+=1; + } + + model_cnt-=1; + } + + make_chunk_reset(); + + self.solid = SOLID_NOT; +// self.effects = EF_NODRAW; + + if(self.trigger_field) + remove(self.trigger_field); +} + +void barrel_go (); +void rep_barrel_wait () +{ +entity item; +//float dist,s1,s2; + +// dprint("Barrel checking to respawn\n"); + item = findradius(self.origin, 256); + while (item) + { +// dprint("Barrel found ents\n"); + if (item.solid&&item.solid!=SOLID_TRIGGER&&item.solid!=SOLID_BSP&&item!=self) + { +// dprint("Barrel found solid\n"); +// dist = vhlen(item.origin-self.origin); +// s1 = item.maxs_x*1.5; +// s2 = 24;//barrel size, at most- 22.6 if 16 by 16 +// if(s1+s2>=dist) + if(overlapped(self,item)) + { +// dprint("Barrel waiting- too close to "); +// dprint(item.classname); +// dprint("\n"); + self.think = rep_barrel_wait; + thinktime self : 2; + return; + } + } + + item = item.chain; + } + barrel_go(); +} + +void spawn_rep_barrel (void) +{ + obj_barrel_fake_chunk_death(); + setorigin(self,self.wallspot); + self.effects=self.flags=self.flags2=self.frame=self.fire_damage=0; + self.enemy=world; + self.classname=self.netname; + self.flags2(+)FL_SUMMONED; + self.angles=self.velocity=self.avelocity='0 0 0'; + self.health=self.max_health; + self.think=rep_barrel_wait; + thinktime self : 0.5; + setmodel(self,"models/null.spr"); +// dprintv("Barrel respawning with %s angles\n",self.angles); +/* + entity replacement; + replacement=spawn(); + replacement.spawnflags=self.spawnflags; + setmodel(replacement,"models/null.spr"); + setorigin(replacement,self.wallspot); + replacement.frags=self.frags; + replacement.classname=self.netname; + replacement.flags2(+)FL_SUMMONED; + replacement.targetname=self.targetname; + replacement.think=rep_barrel_wait; + replacement.nextthink = time + 1; +*/ +} + + + +//BIG FIRE======================================================== + +void burn_out () +{ + if(self.scale>0.1) + { + self.scale-=0.1; + setsize(self.trigger_field,'-24 -24 0'*self.scale,'24 24 48'*self.scale); + thinktime self : 0.01; + self.dmg=self.trigger_field.dmg=self.scale*3; + } + else + { + remove(self.trigger_field); + stopSound(self,0); + remove(self); + } +} + +void spawn_big_fire(vector org) +{ +entity bigfire,oself; + bigfire=spawn(); + + oself=self; + self = bigfire; + + self.dmg=2; + self.classname="big greek fire"; + self.drawflags(+)SCALE_ORIGIN_BOTTOM|DRF_TRANSLUCENT|MLS_FIREFLICKER; + self.scale = 1; + setmodel(self,"models/newfire.mdl"); + setorigin(self,org); + spawn_burnfield(org); + setsize(self.trigger_field,'-48 -48 0','48 48 64'); + sound (self,CHAN_UPDATE+PHS_OVERRIDE_R, "misc/flamloop.wav", 0.5, ATTN_LOOP); + self.think = burn_out; + thinktime self : 30;//burn for 30 seconds + + self=oself; +} + +//GREEK FIRE======================================================== +void obj_barrel_gfire_explode (void) +{ + T_RadiusDamage (self, self, random(150,200), self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_PURIFY2_EXPLODE); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 8); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 8); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 8); + multicast(self.origin,MULTICAST_PHS_R); + + spawn_big_fire(self.origin); + + if(self.spawnflags&BARREL_RESPAWN) + { + spawn_rep_barrel(); +// obj_barrel_fake_chunk_death(); + return; + } + + remove(self); +} + +//void MakeExplosion(string explodemodel); +void()barrel_check_float; + +/*void obj_barrel_gravity() +{ + local vector slope; + + if(self.ltime <= time) + { + slope = getslope(self); + if(slope != self.dest) + { + self.speed = trace_plane_normal_z * 20; + self.ideal_yaw = + self.dest = trace_plane_normal; + } + self.ltime = time + 0.4; + } + + thinktime self : 0.05; +} +*/ + +void float(void) +{ +float x_mod, y_mod, z_mod; +vector org; + + org=self.origin; + if(pointcontents(org)==CONTENT_WATER||pointcontents(org)==CONTENT_SLIME||pointcontents(org)==CONTENT_LAVA) + { + if(self.velocity_x) + self.velocity_x/=1.1; + if(self.velocity_y) + self.velocity_y/=1.1; + + org_z+= self.maxs_z*0.77;//float only 23% above waterlevel + if(pointcontents(org)==CONTENT_WATER||pointcontents(org)==CONTENT_SLIME||pointcontents(org)==CONTENT_LAVA) + { +// self.flags(+)FL_SWIM; + self.flags(-)FL_ONGROUND; + if(self.velocity_z<77) + self.velocity_z=80; + else + self.velocity_z+=random(0,0.01); + } + else + { + self.velocity_z-=random(0,0.01); + } + + if(random()<0.3) + { + y_mod=random(-0.15,0.15); + if(random()<0.5) + self.angles_y+=y_mod; + else + self.angles_y+=y_mod; + } + + if(random()<0.3) + { + x_mod=random(-0.15,0.15); + if(fabs(self.angles_x+x_mod)>10) + self.angles_x-=x_mod; + else + self.angles_x+=x_mod; + } + + if(random()<0.3) + { + z_mod=random(-0.15,0.15); + if(fabs(self.angles_z+z_mod)>10) + self.angles_z-=z_mod; + else + self.angles_z+=z_mod; + } + thinktime self : 0.1; + } + else + { + self.angles_z=self.angles_z=0; + self.classname="barrel"; + self.think=barrel_check_float; + thinktime self : 0.5; + } +} + +void barrel_check_float (void) +{ +vector org; + org=self.origin; + if(pointcontents(org)==CONTENT_WATER||pointcontents(org)==CONTENT_SLIME||pointcontents(org)==CONTENT_LAVA&&(!self.spawnflags&BARREL_SINK)) + { + self.classname=="barrel_floating"; + self.think=float; + thinktime self : 0; + } + else + { + self.classname="barrel"; + self.think=barrel_check_float; + thinktime self : 0.5; + } +} + +/* + * obj_barrel_explode() -- Blows the barrel up. + */ + +void obj_barrel_explode_go() +{ +entity attacker; + + if(self.enemy.flags2&FL_ALIVE)//give credit to person who blew it up + attacker=self.enemy; + else + attacker=self; + + T_RadiusDamage(self, attacker, 200,self);//00, self); + +// sound(self, CHAN_VOICE, "weapons/explode.wav", 1, ATTN_NORM); + + particleexplosion(self.origin + '0 0 83',384,60,40); + + starteffect(CE_LG_EXPLOSION , (self.absmin+self.absmax)*0.5); + + if(self.spawnflags&BARREL_RESPAWN) + { + spawn_rep_barrel(); +// obj_barrel_fake_chunk_death(); + return; + } + + chunk_death(); +} + +void obj_barrel_explode () +{ + //delay so too many don't cause crash + self.th_die=SUB_Null; + self.takedamage = DAMAGE_NO; + + self.think=obj_barrel_explode_go; + if(dmMode==DM_SIEGE) + thinktime self : 0; + else + thinktime self : random()+0.05; +} + +void obj_barrel_use_explode () +{//no delay + self.th_die=SUB_Null; + self.takedamage = DAMAGE_NO; + + self.think=obj_barrel_explode_go; + thinktime self : 0; +} + +void()monster_rat; +void rat_spawn(float offset) +{ + newmis=spawn(); + newmis.angles_y=self.angles_y+offset*60; + newmis.flags2(+)FL_SUMMONED; + if(self.target) + newmis.target=self.target; + makevectors(newmis.angles); + setorigin(newmis,self.origin+v_forward*16); + newmis.think=monster_rat; + thinktime newmis : 0; +} + +void barrel_die () +{ + self.solid=SOLID_NOT; + if(self.model!="models/gfire.mdl") + { + if(random()<0.3||self.target!=""||self.classname=="monster_ratnest") + { + float r; + r=rint(random(3,6)); + while(r>0) + { + rat_spawn(r); + r-=1; + } + } + } + else + { + //particleexplosion(self.origin + '0 0 24',264,60,40); + sound(self,CHAN_AUTO,"raven/outwater.wav",1,ATTN_NORM); + } + + + if(self.spawnflags&BARREL_RESPAWN) + { + spawn_rep_barrel(); +// obj_barrel_fake_chunk_death(); + return; + } + + if(self.classname!="monster_ratnest") + chunk_death(); + else + remove(self); +} + +/* + * obj_barrel_slide() -- Slides a barrel in the direction given in self.movedir. + */ +/* +void obj_barrel_slide() +{ + local entity victim; + local float direction; +//old if function, direction was null +// if(walkmove(direction, self.count) == FALSE) + if(!walkmove(self.cnt, self.count, FALSE)) + { +//Is this supposed to push something else it hits? + victim = findradius(self.origin, self.count + 38); + while(victim) + { + if(victim.movetype != MOVETYPE_NONE && victim != self) + { + direction = vectoyaw(victim.origin - self.origin); + if(self.cnt <= 60 && direction >= 300) + direction -= 360; + if(direction > self.cnt - 60 && + direction < self.cnt + 60) + victim.velocity += (victim.origin - self.origin) * self.count; + } + victim = victim.chain; + } + } + +// if(!self.spawnflags & BARREL_DOWNHILL) +// self.count -= 0.7; +// if(self.count < 0.5) +// self.think = obj_barrel_gravity; +//What is this supposed to do? +// obj_barrel_gravity(); +// reduce self.count to simulate friction, right? + self.count = self.count - 1; + if(self.count<=0) + { + self.think=SUB_Null; + self.nextthink = -1; + } + else + thinktime self : 0.05; +} +*/ + +void obj_barrel_roll (void) +{ + self.v_angle_y=self.angles_y; + self.v_angle_x=self.v_angle_z=0; + makevectors(self.v_angle); + self.velocity-=self.movedir*self.speed; + self.movedir=normalize(v_forward); + self.speed/=1.01; + self.anglespeed=self.speed/7.7; + if(self.speed<1&&self.speed>-1) + { + self.velocity = '0 0 0'; + self.think = SUB_Null; + self.nextthink = -1; + } + else + { + vector dircheck; +// float hitcheck; +//Rolling sound + if(self.flags&FL_ONGROUND) + { + self.flags(-)FL_ONGROUND; + self.last_onground=time; + self.level=TRUE; + } + else if(self.level) + { + self.level=FALSE; + self.last_onground = time - 1; + self.speed/=2;//slow down if go off cliff, looks weird otherwise + } + + + self.velocity+=self.movedir*self.speed; + self.angles_x-=self.anglespeed; + self.think=obj_barrel_roll; + thinktime self : 0.05; + + dircheck=normalize(self.velocity); + makevectors(self.angles); + traceline(self.origin,self.origin+dircheck*39,FALSE,self); + if(trace_fraction==1) + { + traceline(self.origin+v_right*16,self.origin+v_right*16+dircheck*39,FALSE,self); + if(trace_fraction==1) + traceline(self.origin-v_right*16,self.origin-v_right*16+dircheck*39,FALSE,self); + } + if(trace_fraction<1) + { + sound(self,CHAN_AUTO,"fx/thngland.wav",1,ATTN_NORM); // landing thud + self.speed*=-0.25; + self.last_onground=time - 1; + obj_fly_hurt(trace_ent); + self.velocity=dircheck*self.speed; + } + } +} + + +/* + * obj_barrel_shoot() -- Called when a barrel is shot. + */ +void obj_barrel_shoot() +{ + sound(self,CHAN_AUTO,"fx/thngland.wav",1,ATTN_NORM); // landing thud + +// if(self.aflag) +// return; +/* + self.movedir = normalize(self.origin - self.enemy.origin); + self.velocity=self.velocity + self.movedir*self.count; + self.avelocity_y=random(100,300); + self.velocity_z=self.velocity_z + 50; + if(self.velocity_z>150) + self.velocity_z=150; + self.flags(-)FL_ONGROUND; +*/ +} + + +/* + * obj_barrel_use() -- Called when a barrel is triggered. + */ + +void barrel_drop () +{ + self.movetype=MOVETYPE_FLYMISSILE; +// setorigin(self,self.origin - '0 0 20'); + self.flags(-)FL_PUSH|FL_ONGROUND; + self.velocity='0 0 -200'; + self.touch=self.th_die; +} + +void obj_barrel_use() +{ +// if(other.movetype == MOVETYPE_STEP) +// obj_pull(); +// else + obj_barrel_explode(); +} + +void obj_barrel_gfire_light () +{ + self.use=SUB_Null; + self.th_die = obj_barrel_gfire_explode; + sound (self, CHAN_AUTO, "weapons/expsmall.wav", 1, ATTN_NORM); + starteffect(CE_FLOOR_EXPLOSION , self.origin+'0 0 110'); + self.frame=1; + sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,"misc/flamloop.wav",0.5,ATTN_LOOP); + self.effects(+)EF_UPDATESOUND|EF_BRIGHTLIGHT; +} + +void spawn_barrel(float barrel_type) +{ + if(dmMode==DM_SIEGE) + self.spawnflags(+)BARREL_RESPAWN; + + self.frags=barrel_type; + if(!self.flags2&FL_SUMMONED) + { + precache_model("models/barrel.mdl"); + if(barrel_type==BARREL_NORMAL) + precache_model("models/rat.mdl"); + } + + CreateEntityNew(self,ENT_BARREL,"models/barrel.mdl",chunk_death); + + + if(self.spawnflags&ON_SIDE) + { + self.aflag=1; + self.frame=1; + self.v_angle=self.angles; + setsize(self, '-18 -13 -13','18 13 13'); + self.hull=HULL_CROUCH; + } + else + { + setsize(self, '-13 -13 0','13 13 36'); + self.hull=HULL_PLAYER; + } + + if (self.scale) + self.mass *=self.scale; + + self.netname=self.classname; + self.classname = "barrel"; + + self.flags(+)FL_PUSH; + self.touch = obj_push; + self.th_pain = obj_barrel_shoot; + + if (barrel_type==BARREL_NORMAL) + { + self.th_die = barrel_die; + self.skin=0; + } + else if (barrel_type==BARREL_INDESTRUCTIBLE) + { + self.health = 999999; + self.th_die = SUB_Null; + self.skin=1; + } + else if (barrel_type==BARREL_EXPLODING) + { + self.th_die = obj_barrel_explode; + self.skin=2; + } + else if (barrel_type==BARREL_GFIRE) + { + self.th_die = barrel_die; + setmodel(self,"models/gfire.mdl"); + setsize(self,'-16 -16 0','16 16 56'); + self.hull=HULL_PLAYER; + self.use=obj_barrel_gfire_light; + } + + if(!self.spawnflags&BARREL_SINK) + { + self.think=barrel_check_float; + thinktime self : 0; + } + + if(pointcontents(self.origin)!=CONTENT_EMPTY&&(!self.spawnflags&BARREL_SINK)) + { + self.classname="barrel_floating"; + self.think=float; + thinktime self : 0; + } + else if(!self.flags2&FL_SUMMONED&&!self.spawnflags&BARREL_NO_DROP) + droptofloor(); + + if(self.spawnflags&DROP_USE) + { + self.movetype=MOVETYPE_NONE; + self.use=barrel_drop; + if(barrel_type==BARREL_EXPLODING) + self.th_die=obj_barrel_use_explode; + } + else if(self.targetname) + if(barrel_type==BARREL_EXPLODING) + self.use=obj_barrel_use_explode; + else + self.use=self.th_die; + + if(self.spawnflags&BARREL_RESPAWN) + self.wallspot=self.origin; + + spawn_push_trigger(3); +} + + +/*QUAKED obj_barrel (0.3 0.1 0.6) (-13 -13 0) (13 13 36) DOWNHILL NO_DROP ON_SIDE SINK DROP_USE RESPAWN + +A barrel, just a plain old barrel +-------------------------FIELDS------------------------- +.health - How hard it is to smash + Default: 25 +DOWNHILL - This barrel will slide downhill with gravity. +NO_DROP - Will not drop to floor before spawning +ON_SIDE - Will make the barrel appear to be on it's side, the top will point right (90 degrees) + Note- barrels on their side must be placed at least 13 units above the floor. +SINK - Sinks in water +DROP_USE - Barrel has no gravity until used, then will drop +RESPAWN - Barrel will RESPAWN at it's initial origin when it is destroyed +-------------------------------------------------------- +*/ +void obj_barrel(void) +{ + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + precache_sound("misc/squeak.wav"); + if(self.health) + self.max_health=self.health; + spawn_barrel(BARREL_NORMAL); + if(!self.max_health) + self.max_health=self.health; + self.mass = 75; +} + + +/*QUAKED obj_barrel_indestructible (0.3 0.1 0.6) (-13 -13 0) (13 13 36) DOWNHILL NO_DROP ON_SIDE SINK DROP_USE RESPAWN + +A barrel you just can't break +-------------------------FIELDS------------------------- +DOWNHILL - This barrel will slide downhill with gravity. +NO_DROP - Will not drop to floor before spawning +ON_SIDE - Will make the barrel appear to be on it's side, the top will point right (90 degrees) + Note- barrels on their side must be placed at least 13 units above the floor. +SINK - Sinks in water +DROP_USE - Barrel has no gravity until used, then will drop +RESPAWN - Barrel will RESPAWN at it's initial origin when it is destroyed +-------------------------------------------------------- +*/ +void obj_barrel_indestructible(void) +{ + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + if(self.health) + self.max_health=self.health; + spawn_barrel(BARREL_INDESTRUCTIBLE); + if(!self.max_health) + self.max_health=self.health; + self.mass = 95; +} + + +/*QUAKED obj_barrel_exploding (0.3 0.1 0.6) (-13 -13 0) (13 13 36) DOWNHILL NO_DROP ON_SIDE SINK DROP_USE RESPAWN +An exploding barrel with red XXX on the side +WARNING!: Putting too many exploding barrels next to each other will cause a crash, there is no way around this, so if it happens, it's to be considered a Designer error! +Putting them in lines and chains seems to be ok, as long as you don't stack them or group them too closely, more than 4 in a tight group is probably pushing it. +-------------------------FIELDS------------------------- +.health - How hard it is to blow up + Default: 25 +.targetname - set a targetname on a barrel and it will not delay when it explodes (default is arandom delay to prevent too many explosions at once) +DOWNHILL - This barrel will slide downhill with gravity. +NO_DROP - Will not drop to floor before spawning +ON_SIDE - Will make the barrel appear to be on it's side, the top will point right (90 degrees) + Note- barrels on their side must be placed at least 13 units above the floor. +SINK - Sinks in water +DROP_USE - Barrel has no gravity until used, then will drop +RESPAWN - Barrel will RESPAWN at it's initial origin when it is destroyed +-------------------------------------------------------- +*/ +void obj_barrel_exploding(void) +{ + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + if(self.health) + self.max_health=self.health; + spawn_barrel(BARREL_EXPLODING); + if(!self.max_health) + self.max_health=self.health; + self.mass = 85; +} + +/*QUAKED obj_barrel_gfire (0.3 0.1 0.6) (-13 -13 0) (13 13 36) DOWNHILL NO_DROP ON_SIDE SINK DROP_USE RESPAWN +Greek fire barrel +Use a torch to light them +-------------------------FIELDS------------------------- +.health - How hard it is to blow up + Default: 25 +.targetname - set a targetname on a barrel and it will not delay when it explodes (default is arandom delay to prevent too many explosions at once) +DOWNHILL - This barrel will slide downhill with gravity. +NO_DROP - Will not drop to floor before spawning +ON_SIDE - Will make the barrel appear to be on it's side, the top will point right (90 degrees) + Note- barrels on their side must be placed at least 13 units above the floor. +SINK - Sinks in water +DROP_USE - Barrel has no gravity until used, then will drop +RESPAWN - Barrel will RESPAWN at it's initial origin when it is destroyed +-------------------------------------------------------- +*/ +void obj_barrel_gfire(void) +{ + precache_model("models/newfire.mdl"); + precache_model("models/gfire.mdl"); + precache_sound("misc/flamloop.wav"); + precache_sound("misc/gflaunch.wav"); + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + if(self.health) + self.max_health=self.health; + spawn_barrel(BARREL_GFIRE); + self.mass = 100; + if(!self.max_health) + self.max_health=self.health; +} + +void barrel_go(void) +{ +// dprint("Barrel_go: ready to respawn\n"); + if(self.classname=="obj_barrel_normal") + { +// dprint("Respawning normal barrel\n"); + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + spawn_barrel(BARREL_NORMAL); + self.mass = 75; + } + else if(self.classname=="obj_barrel_indestructible") + { +// dprint("Respawning invincible barrel\n"); + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + spawn_barrel(BARREL_INDESTRUCTIBLE); + self.mass = 95; + } + else if(self.classname=="obj_barrel_exploding") + { +// dprint("Respawning explode barrel\n"); + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + spawn_barrel(BARREL_EXPLODING); + self.mass = 100;//85 + } + else if(self.classname=="obj_barrel_gfire") + { +// dprint("Respawning gfire barrel\n"); + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + spawn_barrel(BARREL_GFIRE); + self.mass = 100;//85 + } + else + { +// dprint("NO BARREL TYPE!!!\n"); + if(self.spawnflags&DROP_USE) + self.spawnflags(+)BARREL_NO_DROP; + spawn_barrel(BARREL_EXPLODING); + self.mass = 100;//85 + } +} + diff --git a/bldrain.hc b/bldrain.hc new file mode 100644 index 0000000..caa6370 --- /dev/null +++ b/bldrain.hc @@ -0,0 +1,290 @@ +/* +============================================================================== + +Q:\art\models\weapons\spllbook\spllbook.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\spllbook +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame normal02 normal03 normal04 normal05 normal06 +$frame normal07 normal08 normal09 normal10 normal11 +$frame normal12 normal13 + +// +$frame idlean12 idlean13 idlean14 idlean15 idlean16 +$frame idlean17 idlean18 idlean19 idlean20 idlean21 +$frame idlean22 idlean23 idlean24 idlean25 idlean26 +$frame idlean27 idlean28 idlean29 idlean30 idlean31 +$frame idlean32 idlean33 idlean34 idlean35 + +// +$frame idlebn36 idlebn37 idlebn38 idlebn39 idlebn40 +$frame idlebn41 idlebn42 idlebn43 idlebn44 idlebn45 +$frame idlebn46 idlebn47 idlebn48 idlebn49 idlebn50 +$frame idlebn51 idlebn52 idlebn53 idlebn54 idlebn55 +$frame idlebn56 idlebn57 idlebn58 idlebn59 + + +// +$frame select80 select81 select82 select83 select84 +$frame select85 select86 select87 select88 select89 +$frame select90 select91 select92 select93 select94 +$frame select95 select96 select97 select98 select99 + + +void BloodMissileTouch (void) +{ + if(pointcontents(self.origin)==CONTENT_SKY) + { + remove(self); + return; + } + + if(other.classname==self.classname&&other.owner==self.owner) + return; + + self.movedir=normalize(self.velocity); + + if(!other.takedamage) + { + if(self.frags) + { + //counter for number of bounces + sound (self, CHAN_WEAPON, "succubus/brnbounce.wav", 1, ATTN_NORM); + if(self.dmg>=2) + self.dmg-=1; + starteffect(CE_BRN_BOUNCE,self.origin - self.movedir*8 - '0 0 6','0 0 0',HX_FRAME_TIME);//CreateRedFlash(self.origin); + self.health += 45; + thinktime self : 0; + return; + } + else + { + starteffect(CE_BLDRN_EXPL, self.origin-self.movedir*6,'0 0 0', HX_FRAME_TIME); + sound (self, CHAN_WEAPON, "succubus/brnwall.wav", 1, ATTN_NORM); + remove(self); + return; + } + } + + spawn_touchpuff(self.dmg,other); + T_Damage(other,self,self.owner,self.dmg); + starteffect(CE_BLDRN_EXPL, self.origin-self.movedir*6,'0 0 0', HX_FRAME_TIME); + sound(self,CHAN_AUTO,"succubus/brnhit.wav",1,ATTN_NORM); + + remove(self); +} + +void BloodMissileFade () +{ + self.angles=vectoangles(self.velocity); + if(self.health>30) + { + self.health-=60; + thinktime self : 0.3; + if(self.dmg>=1.75) + self.dmg-=0.75; + } + else + { + remove(self); + return; + } + + traceline(self.origin, self.origin + self.movedir * 240, FALSE, newmis); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_BLOODRAIN); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 240.0); + WriteByte (MSG_MULTICAST, self.health); + multicast(self.origin,MULTICAST_PVS); +} + +void FireBloodMissile (float offset) +{ + float f_dist; + + makevectors(self.v_angle); + + self.effects(+)EF_MUZZLEFLASH; + newmis=spawn(); + newmis.classname="blood missile"; + newmis.owner=self; + newmis.effects(+) EF_NODRAW; + f_dist=8; + if(self.artifact_active&ART_TOMEOFPOWER) + { + newmis.health=250; + newmis.dmg=random(40,60); + f_dist=16; + newmis.solid=SOLID_PHASE; + + newmis.movetype=MOVETYPE_BOUNCEMISSILE; + newmis.frags=TRUE; + } + else + { + newmis.dmg=random(15,22); + newmis.health=90; + newmis.frags=FALSE; + newmis.movetype=MOVETYPE_FLYMISSILE; + } + + newmis.solid=SOLID_BBOX; + newmis.touch=BloodMissileTouch; + + newmis.speed=800; + newmis.velocity=normalize(v_forward)*newmis.speed;// + spread; + newmis.movedir=normalize(newmis.velocity); + newmis.angles=vectoangles(newmis.velocity); + + setmodel(newmis,"models/sucwp1p.mdl"); + setsize(newmis,'0 0 0','0 0 0'); + + setorigin(newmis,self.origin+self.proj_ofs+v_forward*f_dist-v_right*12 + v_right*(offset*3) - '0 0 6'); + weapon_sound(self, "succubus/brnfire.wav"); + + newmis.think=BloodMissileFade; + thinktime newmis : 0.3; + + traceline(newmis.origin, newmis.origin + newmis.movedir * 240, FALSE, newmis); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_BLOODRAIN); + WriteCoord (MSG_MULTICAST, newmis.origin_x); + WriteCoord (MSG_MULTICAST, newmis.origin_y); + WriteCoord (MSG_MULTICAST, newmis.origin_z); + WriteByte (MSG_MULTICAST, newmis.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, newmis.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 240.0); + WriteByte (MSG_MULTICAST, newmis.health); + multicast(self.origin,MULTICAST_PVS); +} + +void blrn_power(float offset) +{ + if(self.attack_finished>time) + return; + + FireBloodMissile(offset); + self.attack_finished=time+0.7; + self.punchangle_x=3; +} + +void blrn_normal() +{ + if(self.attack_finished>time) + return; + + FireBloodMissile(0); + self.attack_finished=time+0.4; +} + + + + + + + + + + +/*====================== +ACTION +select +deselect +ready loop +relax loop +fire once +fire loop +ready to relax(after short delay) +relax to ready(Fire delay? or automatic if see someone?) +=======================*/ + + +void()bloodrain_ready; +void() Suc_Blrn_Fire; + +void bloodrain_fire (void) +{ + if(self.button0&&self.weaponframe==$normal07 &&!self.artifact_active&ART_TOMEOFPOWER) + self.weaponframe=$normal07; + else + self.wfs = advanceweaponframe($normal02,$normal13); + if(self.weaponframe<=$normal07) + self.weaponframe+=1; + self.th_weapon=bloodrain_fire; + self.last_attack=time; + if(self.wfs==WF_CYCLE_WRAPPED) + bloodrain_ready(); + if(self.artifact_active&ART_TOMEOFPOWER) + { +// if(self.weaponframe>=$normal07 && self.weaponframe<=$normal09) +// blrn_power((self.weaponframe - $normal08) *3); + if(self.weaponframe==$normal07) + blrn_power(0); + + } + else if(self.weaponframe==$normal07) + blrn_normal(); +} + +void() Suc_Blrn_Fire = +{ + self.weaponframe_cnt=0; + bloodrain_fire(); + + thinktime self : 0; +}; + +void bloodrain_jellyfingers () +{ + self.wfs = advanceweaponframe($idlebn36,$idlebn59); + self.th_weapon=bloodrain_jellyfingers; + if(self.wfs==WF_CYCLE_WRAPPED) + bloodrain_ready(); +} + +void bloodrain_ready (void) +{ + self.wfs = advanceweaponframe($idlean12,$idlean35); + if(random()<0.1&&self.weaponframe==$idlean35) + self.th_weapon=bloodrain_jellyfingers; + else + self.th_weapon=bloodrain_ready; +} + + +void bloodrain_select (void) +{ + self.wfs = advanceweaponframe($select80,$select99); + self.weaponmodel = "models/sucwp1.mdl"; + self.th_weapon=bloodrain_select; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + bloodrain_ready(); + } +} + +void bloodrain_deselect (void) +{ + self.wfs = advanceweaponframe($select99,$select80); + self.th_weapon=bloodrain_deselect; + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + diff --git a/boner.hc b/boner.hc new file mode 100644 index 0000000..6dd1f4a --- /dev/null +++ b/boner.hc @@ -0,0 +1,512 @@ +/* + * $Header: /HexenWorld/Siege/boner.hc 19 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\spllbook\spllbook.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\spllbook +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame fire1 fire2 fire3 fire4 fire5 +$frame fire6 fire7 fire8 fire9 fire10 +$frame fire11 fire12 + +// +$frame go2mag01 go2mag02 go2mag03 go2mag04 go2mag05 +$frame go2mag06 go2mag07 go2mag08 go2mag09 go2mag10 +$frame go2mag11 go2mag12 go2mag13 + +// +$frame go2shd01 go2shd02 +$frame go2shd03 go2shd04 go2shd05 go2shd06 go2shd07 +$frame go2shd08 go2shd09 go2shd10 go2shd11 go2shd12 +$frame go2shd13 go2shd14 + +// +$frame idle1 idle2 idle3 idle4 idle5 +$frame idle6 idle7 idle8 idle9 idle10 +$frame idle11 idle12 idle13 idle14 idle15 +$frame idle16 idle17 idle18 idle19 idle20 +$frame idle21 idle22 + +// +$frame mfire1 mfire2 mfire3 mfire4 mfire5 +$frame mfire6 mfire7 mfire8 + +// +$frame midle01 midle02 midle03 midle04 midle05 +$frame midle06 midle07 midle08 midle09 midle10 +$frame midle11 midle12 midle13 midle14 midle15 +$frame midle16 midle17 midle18 midle19 midle20 +$frame midle21 midle22 + +// +$frame mselect01 mselect02 mselect03 mselect04 mselect05 +$frame mselect06 mselect07 mselect08 mselect09 mselect10 +$frame mselect11 mselect12 mselect13 mselect14 mselect15 +$frame mselect16 mselect17 mselect18 mselect19 mselect20 + +// +$frame select1 select2 select3 select4 select5 +$frame select6 select7 + + +/* +============================================================================== + +MULTI-DAMAGE + +Collects multiple small damages into a single damage + +============================================================================== +*/ + +float RicochetCount; + +void(vector org)smolder; +void(vector org, float damage) Ricochet = +{ +//float r; + + RicochetCount+=1; + if(RicochetCount > 7) + { + RicochetCount = 0; + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_HWBONERIC); + WriteCoord (MSG_MULTICAST, org_x); + WriteCoord (MSG_MULTICAST, org_y); + WriteCoord (MSG_MULTICAST, org_z); + if(damage > 100) + damage = 100; + WriteByte (MSG_MULTICAST, damage * 2); + multicast(self.origin,MULTICAST_PHS_R); + +/* particle4(org,3,random(368,384),PARTICLETYPE_GRAV,damage*2); + r = random(100); + if (r > 95) + sound (targ,CHAN_AUTO,"weapons/ric1.wav",1,ATTN_NORM); + else if (r > 91) + sound (targ,CHAN_AUTO,"weapons/ric2.wav",1,ATTN_NORM); + else if (r > 87) + sound (targ,CHAN_AUTO,"weapons/ric3.wav",1,ATTN_NORM); +*/ + } + + +}; + +entity multi_ent; +float multi_damage; + +void() ClearMultDamg = +{ + multi_ent = world; + multi_damage = 0; +}; + +void() ApplyMultDamg = +{ +float kicker, inertia; + if (!multi_ent) + return; + +entity loser,winner; + winner=self; + loser=multi_ent; + kicker = multi_damage * 7 - vlen(winner.origin - loser.origin); + if(kicker>0) + { + if(loser.flags&FL_ONGROUND) + { + loser.flags(-)FL_ONGROUND; + loser.velocity_z = loser.velocity_z + 150; + } + if (loser.mass<=10) + inertia = 1; + else inertia = loser.mass/10; + if(loser==self) + loser.velocity = loser.velocity - (normalize(loser.v_angle) * (kicker / inertia)); + else loser.velocity = loser.velocity + (normalize(winner.v_angle) * (kicker / inertia)); + SpawnPuff (loser.origin, loser.velocity*0.1, multi_damage*0.25,loser); + T_Damage (loser, winner, winner, multi_damage); + } +}; + +void(entity hit, float damage) AddMultDamg = +{ + if (!hit) + return; + + if (hit != multi_ent) + { + ApplyMultDamg (); + multi_damage = damage; + multi_ent = hit; + } + else + multi_damage = multi_damage + damage; +}; + +void(float damage, vector dir) TraceHit = +{ + local vector vel, org; + + vel = (normalize(dir + v_factorrange('-1 -1 0','1 1 0')) + 2 * trace_plane_normal) * 200; + org = trace_endpos - dir*4; + + if (trace_ent.takedamage) + { + AddMultDamg (trace_ent, damage); + } + else + Ricochet(org,damage); +}; + +void(float shotcount, vector dir, vector spread) InstantDamage = +{ +vector direction; +vector src; + + makevectors(self.v_angle); + + src = self.origin + self.proj_ofs+'0 0 6'+v_forward*10; + ClearMultDamg (); + while (shotcount > 0) + { + direction = dir + random(-1,1)*spread_x*v_right; + direction += random(-1,1)*spread_y*v_up; + + traceline (src, src + direction*2048, FALSE, self); + if (trace_fraction != 1.0) + TraceHit (4, direction); + shotcount = shotcount - 1; + } + ApplyMultDamg (); +}; + +void bone_shard_touch () +{ + if(other==self.owner) + return; +//string hitsound; + + if(other.takedamage) + { +// hitsound="necro/bonenhit.wav"; + T_Damage(other, self,self.owner,self.dmg); + } + else + { +// hitsound="necro/bonenwal.wav"; + T_RadiusDamage(self,self.owner,self.dmg*2,self.owner); + } +// starteffect(CE_WHITE_SMOKE, self.origin,'0 0 0', HX_FRAME_TIME); +// sound(self,CHAN_WEAPON,hitsound,1,ATTN_NORM); +// particle4(self.origin,3,random(368,384),PARTICLETYPE_GRAV,self.dmg/2); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_HWBONEPOWER2); + if(other.takedamage) + { + WriteByte(MSG_MULTICAST, 1); + } + else + { + WriteByte(MSG_MULTICAST, 0); + } + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS_R); + + + remove(self); +} + +void bone_shard_touch2 (void) +{ + endeffect(MSG_ALL,self.wrq_effect_id); + bone_shard_touch(); +} + +void bone_removeshrapnel (void) +{ + remove(self); +} + +// shrapnel is too much net hit, will be faked by client only shards +// although the server will have invisible shards for damage determination +void fire_bone_shrapnel () +{ +vector shard_vel; + newmis=spawn(); + newmis.classname = "bone_fake_shrapnel"; //so reflection won't send turneffect + newmis.owner=self.owner; + newmis.movetype=MOVETYPE_BOUNCE; + newmis.solid=SOLID_PHASE; + newmis.effects (+) EF_NODRAW; + newmis.touch=bone_shard_touch; + newmis.dmg=15; + newmis.think=bone_removeshrapnel; + thinktime newmis : 3; + + newmis.speed=777; + trace_fraction=0; + trace_ent=world; + while(trace_fraction!=1&&!trace_ent.takedamage) + { + shard_vel=randomv('1 1 1','-1 -1 -1'); + traceline(self.origin,self.origin+shard_vel*36,TRUE,self); + } + newmis.velocity=shard_vel*newmis.speed; + newmis.avelocity=randomv('777 777 777','-777 -777 -777'); + +// setmodel(newmis,"models/boneshrd.mdl"); + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,self.origin+shard_vel*8); + +// newmis.wrq_effect_id = starteffect(CE_BONESHRAPNEL, newmis.origin, newmis.velocity, +// newmis.angles,newmis.avelocity); + +} + +void bone_shatter () +{ +float shard_count; + endeffect(MSG_ALL,self.wrq_effect_id); + + shard_count=20; + while(shard_count) + { + fire_bone_shrapnel(); + shard_count-=1; + } +} + +void bone_power_touch () +{ +//vector randomvec; + +// sound(self,CHAN_WEAPON,"necro/bonephit.wav",1,ATTN_NORM); + if(other.takedamage) + { + T_Damage(other, self,self.owner,self.dmg*2); + } + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_HWBONEPOWER); + if(other.takedamage) + { + WriteByte (MSG_MULTICAST, 4); //number of ghosts + } + else + { + WriteByte(MSG_MULTICAST, 0); //no ghosts + } + + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteCoord (MSG_MULTICAST, self.movedir_x); + WriteCoord (MSG_MULTICAST, self.movedir_y); + WriteCoord (MSG_MULTICAST, self.movedir_z); + multicast(self.origin,MULTICAST_PHS_R); + + + self.solid=SOLID_NOT; + self.flags2(+)FL2_ADJUST_MON_DAM; + T_RadiusDamage(self,self.owner,self.dmg,other); + + bone_shatter(); +/* dprint("Doing final effect\n"); + starteffect(CE_BONE_EXPLOSION, self.origin-self.movedir*6,'0 0 0', HX_FRAME_TIME); + particle4(self.origin,50,random(368,384),PARTICLETYPE_GRAV,10); + dprint("removing\n"); +*/ remove(self); +} + +void bone_fire(float powered_up, vector ofs) +{ +//SOUND +vector org; + + makevectors(self.v_angle); + newmis=spawn(); + newmis.owner=self; + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.solid=SOLID_BBOX; + newmis.speed=1000; + + org=self.origin+self.proj_ofs+v_forward*8+v_right*(ofs_y+12)+v_up*ofs_z; + setorigin(newmis,org); + + if(powered_up) + { + newmis.velocity=v_forward*newmis.speed; + self.punchangle_x=-2; +// sound(self,CHAN_WEAPON,"necro/bonefpow.wav",1,ATTN_NORM); + self.attack_finished=time + 1.3; + newmis.classname = "bone_powered"; + newmis.dmg=80;//was 200 + newmis.frags=TRUE; +// newmis.takedamage=DAMAGE_YES; +// newmis.health=3; +// newmis.th_die=bone_shatter; + newmis.touch=bone_power_touch; +// newmis.avelocity=randomv('777 777 777','-777 -777 -777'); +// setmodel(newmis,"models/bonelump.mdl"); + setsize(newmis,'0 0 0','0 0 0'); + self.greenmana-=20; + newmis.effects (+) EF_NODRAW; + org = randomv('777 777 777','-777 -777 -777'); + newmis.wrq_effect_id = starteffect(CE_HWBONEBALL, newmis.origin, newmis.velocity, + newmis.angles,org); + } + else + { + newmis.classname = "bone_normal"; + newmis.speed+=random(500); + newmis.velocity=v_forward*newmis.speed; + newmis.dmg=10; + newmis.touch=bone_shard_touch2; + newmis.effects (+) EF_NODRAW; +// setmodel(newmis,"models/boneshot.mdl"); + setsize(newmis,'0 0 0','0 0 0'); +// newmis.velocity+=v_right*ofs_y*10+v_up*ofs_z*10; + +// newmis.angles=vectoangles(newmis.velocity); +// newmis.avelocity_z=random(777,-777); + + newmis.wrq_effect_id = starteffect(CE_BONESHARD, newmis.origin, newmis.velocity); + } +} + +void bone_normal() +{ +vector dir; +//sound +// sound(self,CHAN_WEAPON,"necro/bonefnrm.wav",1,ATTN_NORM); + self.effects(+)EF_MUZZLEFLASH; + makevectors(self.v_angle); + dir=normalize(v_forward); + InstantDamage(4,dir,'0.1 0.1 0.1'); +// InstantDamage(12,dir,'0.1 0.1 0.1'); + self.greenmana-=0.5; + self.attack_finished=time+0.3; +} + +void bone_fire_once() +{ +vector ofs; + ofs_z=random(-5,5); + ofs_x=random(-5,5); + ofs_y=random(-5,5); + bone_fire(FALSE,ofs); +} + + +/*====================== +ACTION +select +deselect +ready loop +relax loop +fire once +fire loop +ready to relax(after short delay) +relax to ready(Fire delay? or automatic if see someone?) +=======================*/ + + +void()boneshard_ready; +void() Nec_Bon_Attack; + + +void boneshard_fire (void) +{ + self.wfs = advanceweaponframe($fire1,$fire12); + if(self.button0&&self.weaponframe>$fire3 &&!self.artifact_active&ART_TOMEOFPOWER) + self.weaponframe=$fire3; + self.th_weapon=boneshard_fire; + self.last_attack=time; + if(self.wfs==WF_CYCLE_WRAPPED||self.greenmana<1||(self.greenmana<10&&self.artifact_active&ART_TOMEOFPOWER)) + boneshard_ready(); + else if(self.weaponframe==$fire3) + if(self.artifact_active&ART_TOMEOFPOWER) + bone_fire(TRUE,'0 0 0'); + else + bone_normal(); + + if(random()<0.5&&!self.artifact_active&ART_TOMEOFPOWER&&self.weaponframe<=$fire6) + bone_fire_once(); +} + +void() Nec_Bon_Attack = +{ + boneshard_fire(); + + thinktime self : 0; +}; + +void boneshard_jellyfingers () +{ + self.wfs = advanceweaponframe($idle1,$idle22); + self.th_weapon=boneshard_jellyfingers; + if(self.wfs==WF_CYCLE_WRAPPED) + boneshard_ready(); +} + +void boneshard_ready (void) +{ + self.weaponframe=$idle1; + if(random()<0.1&&random()<0.3&&random()<0.5) + self.th_weapon=boneshard_jellyfingers; + else + self.th_weapon=boneshard_ready; +} + +void boneshard_select (void) +{ + self.wfs = advanceweaponframe($select7,$select1); + self.weaponmodel = "models/spllbook.mdl"; + self.th_weapon=boneshard_select; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + boneshard_ready(); + } +} + +void boneshard_deselect (void) +{ + self.wfs = advanceweaponframe($select1,$select7); + self.th_weapon=boneshard_deselect; + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + + +void boneshard_select_from_mmis (void) +{ + self.wfs = advanceweaponframe($go2shd01,$go2shd14); + self.weaponmodel = "models/spllbook.mdl"; + self.th_weapon=boneshard_select_from_mmis; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + boneshard_ready(); + } +} + diff --git a/boss.hc b/boss.hc new file mode 100644 index 0000000..efc3ad2 --- /dev/null +++ b/boss.hc @@ -0,0 +1,395 @@ +/* + * $Header: /HexenWorld/Siege/Boss.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +BOSS-ONE + +============================================================================== +*/ +$cd id1/models/boss1 +$origin 0 0 -15 +$base base +$skin skin +$scale 5 + +$frame rise1 rise2 rise3 rise4 rise5 rise6 rise7 rise8 rise9 rise10 +$frame rise11 rise12 rise13 rise14 rise15 rise16 rise17 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 +$frame walk9 walk10 walk11 walk12 walk13 walk14 walk15 +$frame walk16 walk17 walk18 walk19 walk20 walk21 walk22 +$frame walk23 walk24 walk25 walk26 walk27 walk28 walk29 walk30 walk31 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 + +$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8 +$frame attack9 attack10 attack11 attack12 attack13 attack14 attack15 +$frame attack16 attack17 attack18 attack19 attack20 attack21 attack22 +$frame attack23 + +$frame shocka1 shocka2 shocka3 shocka4 shocka5 shocka6 shocka7 shocka8 +$frame shocka9 shocka10 + +$frame shockb1 shockb2 shockb3 shockb4 shockb5 shockb6 + +$frame shockc1 shockc2 shockc3 shockc4 shockc5 shockc6 shockc7 shockc8 +$frame shockc9 shockc10 + + +void(vector p) boss_missile; + +void() boss_face = +{ + +// go for another player if multi player + if (self.enemy.health <= 0 || random() < 0.02) + { + self.enemy = find(self.enemy, classname, "player"); + if (!self.enemy) + self.enemy = find(self.enemy, classname, "player"); + } + ai_face(); +}; + +void() boss_rise1 =[ $rise1, boss_rise2 ] { +sound (self, CHAN_WEAPON, "boss1/out1.wav", 1, ATTN_NORM); +}; +void() boss_rise2 =[ $rise2, boss_rise3 ] { +sound (self, CHAN_VOICE, "boss1/sight1.wav", 1, ATTN_NORM); +}; +void() boss_rise3 =[ $rise3, boss_rise4 ] {}; +void() boss_rise4 =[ $rise4, boss_rise5 ] {}; +void() boss_rise5 =[ $rise5, boss_rise6 ] {}; +void() boss_rise6 =[ $rise6, boss_rise7 ] {}; +void() boss_rise7 =[ $rise7, boss_rise8 ] {}; +void() boss_rise8 =[ $rise8, boss_rise9 ] {}; +void() boss_rise9 =[ $rise9, boss_rise10 ] {}; +void() boss_rise10 =[ $rise10, boss_rise11 ] {}; +void() boss_rise11 =[ $rise11, boss_rise12 ] {}; +void() boss_rise12 =[ $rise12, boss_rise13 ] {}; +void() boss_rise13 =[ $rise13, boss_rise14 ] {}; +void() boss_rise14 =[ $rise14, boss_rise15 ] {}; +void() boss_rise15 =[ $rise15, boss_rise16 ] {}; +void() boss_rise16 =[ $rise16, boss_rise17 ] {}; +void() boss_rise17 =[ $rise17, boss_missile1 ] {}; + +void() boss_idle1 =[ $walk1, boss_idle2 ] +{ +// look for other players +}; +void() boss_idle2 =[ $walk2, boss_idle3 ] {boss_face();}; +void() boss_idle3 =[ $walk3, boss_idle4 ] {boss_face();}; +void() boss_idle4 =[ $walk4, boss_idle5 ] {boss_face();}; +void() boss_idle5 =[ $walk5, boss_idle6 ] {boss_face();}; +void() boss_idle6 =[ $walk6, boss_idle7 ] {boss_face();}; +void() boss_idle7 =[ $walk7, boss_idle8 ] {boss_face();}; +void() boss_idle8 =[ $walk8, boss_idle9 ] {boss_face();}; +void() boss_idle9 =[ $walk9, boss_idle10 ] {boss_face();}; +void() boss_idle10 =[ $walk10, boss_idle11 ] {boss_face();}; +void() boss_idle11 =[ $walk11, boss_idle12 ] {boss_face();}; +void() boss_idle12 =[ $walk12, boss_idle13 ] {boss_face();}; +void() boss_idle13 =[ $walk13, boss_idle14 ] {boss_face();}; +void() boss_idle14 =[ $walk14, boss_idle15 ] {boss_face();}; +void() boss_idle15 =[ $walk15, boss_idle16 ] {boss_face();}; +void() boss_idle16 =[ $walk16, boss_idle17 ] {boss_face();}; +void() boss_idle17 =[ $walk17, boss_idle18 ] {boss_face();}; +void() boss_idle18 =[ $walk18, boss_idle19 ] {boss_face();}; +void() boss_idle19 =[ $walk19, boss_idle20 ] {boss_face();}; +void() boss_idle20 =[ $walk20, boss_idle21 ] {boss_face();}; +void() boss_idle21 =[ $walk21, boss_idle22 ] {boss_face();}; +void() boss_idle22 =[ $walk22, boss_idle23 ] {boss_face();}; +void() boss_idle23 =[ $walk23, boss_idle24 ] {boss_face();}; +void() boss_idle24 =[ $walk24, boss_idle25 ] {boss_face();}; +void() boss_idle25 =[ $walk25, boss_idle26 ] {boss_face();}; +void() boss_idle26 =[ $walk26, boss_idle27 ] {boss_face();}; +void() boss_idle27 =[ $walk27, boss_idle28 ] {boss_face();}; +void() boss_idle28 =[ $walk28, boss_idle29 ] {boss_face();}; +void() boss_idle29 =[ $walk29, boss_idle30 ] {boss_face();}; +void() boss_idle30 =[ $walk30, boss_idle31 ] {boss_face();}; +void() boss_idle31 =[ $walk31, boss_idle1 ] {boss_face();}; + +void() boss_missile1 =[ $attack1, boss_missile2 ] {boss_face();}; +void() boss_missile2 =[ $attack2, boss_missile3 ] {boss_face();}; +void() boss_missile3 =[ $attack3, boss_missile4 ] {boss_face();}; +void() boss_missile4 =[ $attack4, boss_missile5 ] {boss_face();}; +void() boss_missile5 =[ $attack5, boss_missile6 ] {boss_face();}; +void() boss_missile6 =[ $attack6, boss_missile7 ] {boss_face();}; +void() boss_missile7 =[ $attack7, boss_missile8 ] {boss_face();}; +void() boss_missile8 =[ $attack8, boss_missile9 ] {boss_face();}; +void() boss_missile9 =[ $attack9, boss_missile10 ] {boss_missile('100 100 200');}; +void() boss_missile10 =[ $attack10, boss_missile11 ] {boss_face();}; +void() boss_missile11 =[ $attack11, boss_missile12 ] {boss_face();}; +void() boss_missile12 =[ $attack12, boss_missile13 ] {boss_face();}; +void() boss_missile13 =[ $attack13, boss_missile14 ] {boss_face();}; +void() boss_missile14 =[ $attack14, boss_missile15 ] {boss_face();}; +void() boss_missile15 =[ $attack15, boss_missile16 ] {boss_face();}; +void() boss_missile16 =[ $attack16, boss_missile17 ] {boss_face();}; +void() boss_missile17 =[ $attack17, boss_missile18 ] {boss_face();}; +void() boss_missile18 =[ $attack18, boss_missile19 ] {boss_face();}; +void() boss_missile19 =[ $attack19, boss_missile20 ] {boss_face();}; +void() boss_missile20 =[ $attack20, boss_missile21 ] {boss_missile('100 -100 200');}; +void() boss_missile21 =[ $attack21, boss_missile22 ] {boss_face();}; +void() boss_missile22 =[ $attack22, boss_missile23 ] {boss_face();}; +void() boss_missile23 =[ $attack23, boss_missile1 ] {boss_face();}; + +void() boss_shocka1 =[ $shocka1, boss_shocka2 ] {}; +void() boss_shocka2 =[ $shocka2, boss_shocka3 ] {}; +void() boss_shocka3 =[ $shocka3, boss_shocka4 ] {}; +void() boss_shocka4 =[ $shocka4, boss_shocka5 ] {}; +void() boss_shocka5 =[ $shocka5, boss_shocka6 ] {}; +void() boss_shocka6 =[ $shocka6, boss_shocka7 ] {}; +void() boss_shocka7 =[ $shocka7, boss_shocka8 ] {}; +void() boss_shocka8 =[ $shocka8, boss_shocka9 ] {}; +void() boss_shocka9 =[ $shocka9, boss_shocka10 ] {}; +void() boss_shocka10 =[ $shocka10, boss_missile1 ] {}; + +void() boss_shockb1 =[ $shockb1, boss_shockb2 ] {}; +void() boss_shockb2 =[ $shockb2, boss_shockb3 ] {}; +void() boss_shockb3 =[ $shockb3, boss_shockb4 ] {}; +void() boss_shockb4 =[ $shockb4, boss_shockb5 ] {}; +void() boss_shockb5 =[ $shockb5, boss_shockb6 ] {}; +void() boss_shockb6 =[ $shockb6, boss_shockb7 ] {}; +void() boss_shockb7 =[ $shockb1, boss_shockb8 ] {}; +void() boss_shockb8 =[ $shockb2, boss_shockb9 ] {}; +void() boss_shockb9 =[ $shockb3, boss_shockb10 ] {}; +void() boss_shockb10 =[ $shockb4, boss_missile1 ] {}; + +void() boss_shockc1 =[ $shockc1, boss_shockc2 ] {}; +void() boss_shockc2 =[ $shockc2, boss_shockc3 ] {}; +void() boss_shockc3 =[ $shockc3, boss_shockc4 ] {}; +void() boss_shockc4 =[ $shockc4, boss_shockc5 ] {}; +void() boss_shockc5 =[ $shockc5, boss_shockc6 ] {}; +void() boss_shockc6 =[ $shockc6, boss_shockc7 ] {}; +void() boss_shockc7 =[ $shockc7, boss_shockc8 ] {}; +void() boss_shockc8 =[ $shockc8, boss_shockc9 ] {}; +void() boss_shockc9 =[ $shockc9, boss_shockc10 ] {}; +void() boss_shockc10 =[ $shockc10, boss_death1 ] {}; + +void() boss_death1 = [$death1, boss_death2] { +sound (self, CHAN_VOICE, "boss1/death.wav", 1, ATTN_NORM); +}; +void() boss_death2 = [$death2, boss_death3] {}; +void() boss_death3 = [$death3, boss_death4] {}; +void() boss_death4 = [$death4, boss_death5] {}; +void() boss_death5 = [$death5, boss_death6] {}; +void() boss_death6 = [$death6, boss_death7] {}; +void() boss_death7 = [$death7, boss_death8] {}; +void() boss_death8 = [$death8, boss_death9] {}; +void() boss_death9 = [$death9, boss_death10] +{ + sound (self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM); + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LAVASPLASH); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); +}; + +void() boss_death10 = [$death9, boss_death10] +{ + killed_monsters = killed_monsters + 1; + WriteByte (MSG_ALL, SVC_KILLEDMONSTER); // FIXME: reliable broadcast + SUB_UseTargets (); + remove (self); +}; + +void(vector p) boss_missile = +{ + local vector offang; + local vector org, vec, d; + local float t; + + offang = vectoangles (self.enemy.origin - self.origin); + makevectors (offang); + + org = self.origin + p_x*v_forward + p_y*v_right + p_z*'0 0 1'; + +// lead the player on hard mode + if (skill > 1) + { + t = vlen(self.enemy.origin - org) / 300; + vec = self.enemy.velocity; + vec_z = 0; + d = self.enemy.origin + t * vec; + } + else + { + d = self.enemy.origin; + } + + vec = normalize (d - org); + + launch_spike (org, vec); + setmodel (newmis, "progs/lavaball.mdl"); + newmis.avelocity = '200 100 300'; + setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); + newmis.velocity = vec*300; + newmis.touch = T_MissileTouch; // rocket explosion + sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); + +// check for dead enemy + if (self.enemy.health <= 0) + boss_idle1 (); +}; + + +void() boss_awake = +{ + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.takedamage = DAMAGE_NO; + + setmodel (self, "progs/boss.mdl"); + setsize (self, '-128 -128 -24', '128 128 256'); + + if (skill == 0) + self.health = 1; + else + self.health = 3; + + self.enemy = activator; + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LAVASPLASH); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + + self.yaw_speed = 20; + boss_rise1 (); +}; + + +/*QUAK-ED monster_boss (1 0 0) (-128 -128 -24) (128 128 256) +Monster Boss +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void() monster_boss = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/boss.mdl"); + precache_model ("progs/lavaball.mdl"); + + precache_sound ("weapons/rocket1i.wav"); + precache_sound ("boss1/out1.wav"); + precache_sound ("boss1/sight1.wav"); + precache_sound ("misc/power.wav"); + precache_sound ("boss1/throw.wav"); + precache_sound ("boss1/pain.wav"); + precache_sound ("boss1/death.wav"); + + total_monsters = total_monsters + 1; + + self.use = boss_awake; +}; + +//=========================================================================== + +entity le1, le2; +float lightning_end; + +void() lightning_fire = +{ + local vector p1, p2; + + if (time >= lightning_end) + { // done here, put the terminals back up + self = le1; + door_go_down (); + self = le2; + door_go_down (); + return; + } + + p1 = (le1.mins + le1.maxs) * 0.5; + p1_z = le1.absmin_z - 16; + + p2 = (le2.mins + le2.maxs) * 0.5; + p2_z = le2.absmin_z - 16; + + // compensate for length of bolt + p2 = p2 - normalize(p2-p1)*100; + + self.nextthink = time + 0.1; + self.think = lightning_fire; + + WriteByte (MSG_ALL, SVC_TEMPENTITY); + WriteByte (MSG_ALL, TE_LIGHTNING3); + WriteEntity (MSG_ALL, world); + WriteCoord (MSG_ALL, p1_x); + WriteCoord (MSG_ALL, p1_y); + WriteCoord (MSG_ALL, p1_z); + WriteCoord (MSG_ALL, p2_x); + WriteCoord (MSG_ALL, p2_y); + WriteCoord (MSG_ALL, p2_z); +}; + +void() lightning_use = +{ + if (lightning_end >= time + 1) + return; + + le1 = find( world, target, "lightning"); + le2 = find( le1, target, "lightning"); + if (!le1 || !le2) + { + dprint ("missing lightning targets\n"); + return; + } + + if ( + (le1.state != STATE_TOP && le1.state != STATE_BOTTOM) + || (le2.state != STATE_TOP && le2.state != STATE_BOTTOM) + || (le1.state != le2.state) ) + { +// dprint ("not aligned\n"); + return; + } + +// don't let the electrodes go back up until the bolt is done + le1.nextthink = -1; + le2.nextthink = -1; + lightning_end = time + 1; + + sound (self, CHAN_VOICE, "misc/power.wav", 1, ATTN_NORM); + lightning_fire (); + +// advance the boss pain if down + self = find (world, classname, "monster_boss"); + if (!self) + return; + self.enemy = activator; + if (le1.state == STATE_TOP && self.health > 0) + { + sound (self, CHAN_VOICE, "boss1/pain.wav", 1, ATTN_NORM); + self.health = self.health - 1; + if (self.health >= 2) + boss_shocka1(); + else if (self.health == 1) + boss_shockb1(); + else if (self.health == 0) + boss_shockc1(); + } +}; + + +/*QUAK-ED event_lightning (0 1 1) (-16 -16 -16) (16 16 16) +Just for boss level. +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void() event_lightning = +{ + self.use = lightning_use; +}; + diff --git a/boulder.hc b/boulder.hc new file mode 100644 index 0000000..0c0f533 --- /dev/null +++ b/boulder.hc @@ -0,0 +1,185 @@ +/* + * $Header: /HexenWorld/Siege/boulder.hc 3 5/25/98 1:38p Mgummelt $ + */ + +$cd \art\models\objects\boulder\final +$base base 128 128 +$skin skin +$frame resting + +void() boulder_find_path; + +//============================================================================ + +void(entity targ) boulder_moveto_target = +{ + SUB_CalcMove(targ.origin, 50, boulder_find_path); + if (!targ.target) remove(self); + else self.target = targ.target; +}; + +void() boulder_next = +{ + local entity targ; + + dprint("finding path\n"); + + targ = find(world, targetname, self.target); + + if (!targ) remove(self); + + boulder_moveto_target(targ); +}; + +void() boulder_find_path = +{ + local entity targ; + + dprint("finding path\n"); + + targ = find(world, targetname, self.target); + + if (!targ) remove(self); + + self.target = targ.target; + + self.nextthink = self.ltime + 0.1; + self.think = boulder_next; +}; + +//============================================================================ +vector() BoulderChunkVelocity = +{ + local vector v; + + v = randomv('-140 -140 70', '140 140 210'); + + return v; +}; + +void(vector space) BoulderCreateSpriteChunks = +{ + local entity sprite; + + sprite = spawn(); + + space = randomv(space); + + setorigin (sprite, self.absmin + space); + setmodel (sprite, "gfx/stone.spr"); + + setsize (sprite, '0 0 0', '0 0 0'); + sprite.movetype = MOVETYPE_BOUNCE; + sprite.solid = SOLID_NOT; + sprite.velocity = BoulderChunkVelocity(); + sprite.think = SUB_Remove; + sprite.ltime = time; + sprite.nextthink = time + 1 + random()*1; +}; + +void(vector space) BoulderCreateModelChunks = +{ + local entity chunk; + + chunk = spawn(); + + space_x = space_x * random(); + space_y = space_y * random(); + space_z = space_z * random(); + + setorigin (chunk, self.absmin + space); + setmodel (chunk, "models/shard.mdl"); + chunk.skin=1; + + setsize (chunk, '0 0 0', '0 0 0'); + chunk.movetype = MOVETYPE_BOUNCE; + chunk.solid = SOLID_NOT; + chunk.velocity = BoulderChunkVelocity(); + chunk.think = SUB_Remove; + chunk.avelocity_x = random()*1200; + chunk.avelocity_y = random()*1200; + chunk.avelocity_z = random()*1200; + chunk.ltime = time; + chunk.nextthink = time + 1 + random(); +}; + +void() boulder_die = +{ + local vector space; + local float holdcount,spritecount,chunkcount; + + space = self.absmax - self.absmin; + + holdcount = space_x + space_y + space_z; + + spritecount = holdcount/8; + chunkcount = holdcount/16; + + sound (self, CHAN_VOICE, "raven/wallbrk.wav", 1, ATTN_NORM); + + while (spritecount>0) + { + // CreateSpriteChunks(space); + spritecount = spritecount - 1; + } + + while (chunkcount>0) + { + BoulderCreateModelChunks(space); + chunkcount = chunkcount - 1; + } + + remove(self); +}; + +void() boulder_crush = +{ + dprint("Crusha!\n"); + T_Damage (other, self, self, 50); +}; + +void() boulder_use = +{ + self.velocity_x = 100 * random(); + self.velocity_y = 100 * random(); + self.velocity_z = 400; + + self.avelocity_x = random()*1200; + self.avelocity_y = random()*1200; + self.avelocity_z = random()*1200; + + self.movetype = MOVETYPE_BOUNCE; +}; + +/*QUAKED trap_boulder (0.3 0.1 0.6) (-13 -13 -14) (13 13 22) +A boulder +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void() trap_boulder = +{ + local entity boulder; + + boulder = spawn(); + + precache_model2("models/boulder.mdl"); + setmodel(self, "models/boulder.mdl"); + + self.health = 75; + self.max_health = self.health; + + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_BOUNCE; + + self.th_die = boulder_die; + //self.touch = boulder_use; + self.blocked = boulder_crush; + //self.use= boulder_use; + + self.takedamage = DAMAGE_YES; + + self.think = boulder_find_path; + self.nextthink = self.ltime + 0.1; +}; + diff --git a/breakabl.hc b/breakabl.hc new file mode 100644 index 0000000..3fc1317 --- /dev/null +++ b/breakabl.hc @@ -0,0 +1,363 @@ +/* + * $Header: /HexenWorld/Siege/breakabl.hc 7 5/31/98 2:58p Mgummelt $ + */ + +/* +============================================================================== + +BREAKABLE BRUSHES + +============================================================================== +*/ + +float BREAK_KILLALL = 1; +float BREAK_HIERARCH = 2; +float BREAK_NOLINK = 4; +float BREAK_CHECKNAME = 8; +float BREAK_ORDERED = 16; +float BREAK_TRANSLUCENT = 32; +float BREAK_INVINCIBLE = 64; +float BREAK_INVISIBLE = 128; + +float (entity e1, entity e2) EntitiesTouching; + +float breakhealth[21] = +{ + 0, + 75, // THINGTYPE_GREYSTONE + 50, // THINGTYPE_WOOD + 100, // THINGTYPE_METAL + 30, // THINGTYPE_FLESH + 999, // THINGTYPE_FIRE + 25, // THINGTYPE_CLAY + 35, // THINGTYPE_LEAVES + 35, // THINGTYPE_HAY + 75, // THINGTYPE_BROWNSTONE + 35, // THINGTYPE_CLOTH + 35, // THINGTYPE_WOOD_LEAF + 75, // THINGTYPE_WOOD_METAL + 65, // THINGTYPE_WOOD_STONE + 90, // THINGTYPE_METAL_STONE + 60, // THINGTYPE_METAL_CLOTH + 10, // THINGTYPE_WEB + 10, // THINGTYPE_GLASS + 50, // THINGTYPE_ICE + 10, // THINGTYPE_CLEARCLASS + 10 // THINGTYPE_CLEARCLASS +}; + +//============================================================================ + +void linkBreakables() +{ + local entity t, starte; + local vector cmins, cmaxs; + + if (self.enemy) return; // already linked by another breakable + + if (self.spawnflags & BREAK_NOLINK) + { + self.owner = self.enemy = self; + return; // don't want to link this door + } + + cmins = self.mins; + cmaxs = self.maxs; + + starte = self; + t = self; + + do + { + self.owner = starte; // master breakable + + if (self.health) starte.health = self.health; + if (self.targetname) starte.targetname = self.targetname; + + t = find (t, classname, self.classname); + if (!t) + { + self.enemy = starte; // make the chain a loop + + self = self.owner; + + if (self.health) return; + if (self.targetname) return; + if (self.items) return; + + return; + } + + if (EntitiesTouching(self,t) && + (((self.spawnflags & BREAK_CHECKNAME) && (self.netname == t.netname)) || + (!self.spawnflags & BREAK_CHECKNAME))) + { + + if (t.enemy) + { + //dprint("cross connected brushes!!\n"); + return; + } + + self.enemy = t; + self = t; + + if (t.mins_x < cmins_x) + cmins_x = t.mins_x; + if (t.mins_y < cmins_y) + cmins_y = t.mins_y; + if (t.mins_z < cmins_z) + cmins_z = t.mins_z; + if (t.maxs_x > cmaxs_x) + cmaxs_x = t.maxs_x; + if (t.maxs_y > cmaxs_y) + cmaxs_y = t.maxs_y; + if (t.maxs_z > cmaxs_z) + cmaxs_z = t.maxs_z; + } + } while (1); +} + + +//============================================================================ +void brush_use_hierarchy() +{ + local entity starte, oself, other; + local float headNum; + + oself = starte = self; + headNum = self.frags; + + do + { + if (self.frags >= headNum) + self.th_die(); + + self = self.enemy; + } while ( (self != starte) && (self != world) && (self.frags != self.cnt)); +} + + +void brush_use_ordered() +{ + local entity starte, oself; + + starte = oself = self; + + self.health = self.max_health; + + if (self.frags == self.cnt) + self.th_die(); + else do + { + self = self.enemy; + } while ( (self != oself) && (self != world) && (self.frags != self.cnt)); + + if (self.frags == self.cnt && self != world && self != oself) self.th_die(); + + do + { + oself.cnt += 1; + oself = oself.enemy; + } while ( (oself != starte) && (oself != world) ); +} + + +void brush_use() +{ + local entity starte, other; + + starte = self; + + activator = other; + + if (starte.spawnflags & BREAK_KILLALL) + { + do + { + other = self.enemy; + self.th_die(); + self = other; + } while ( (self != starte) && (self != world) ); + } + else + { +// dprint("Chunkalicious baby!\n"); + self.th_die(); + } +} + +void brush_no_link_use (void) +{ +//entity found, starte; + + SUB_UseTargets(); +/* if(self.target) + { + found=find(found,targetname,self.target); + if(found!=world) + { + starte=found; + found.think=found.use; + thinktime found : 0; + found=find(found,targetname,self.target); + while(found!=starte&&found!=world) + { + found.think=found.use; + thinktime found : 0; + found=find(found,targetname,self.target); + } + } + } +*/ + self.th_die(); +} + +void breakable_hurt_use(entity attacker,float total_damage) +{ +string otarg; + otarg = self.target; + self.target = self.pain_target; + activator=attacker; + SUB_UseTargets(); + self.target = otarg; +} + +/*QUAKED breakable_brush (0 0 1) ? KILLALL HIERARCH NOLINK CHECKNAME ORDERED TRANSLUCENT INVINCIBLE INVISIBLE +Breakable window or wall + +You can manually control the heirarchy of breaking by targeting all the brushes you want this brush to break. +If you target a light with this object and turn on the "breaklight" spawnflag, it will turn off that light when it's broken. The light will default to 300 if no lightvalue1 is given. + +AUTOMATIC LINKING OPTIONS: +killall - when killed, the brush will kill all connected brushes +hierarch - link all brushes in a hierarchy. The hierarchy priority is set in the + frags field of each brush. Lower numbers will kill higher numbers. If + brushes share the same priority, they will die at the same time. +nolink - don't automatically link this brush with other brushes (use only manual targeting to link) +checkname - link brushes, but also check the name you place in the netname field. + Brushes must then not only touch, but also have the same netname to link +ordered - like hierarch, except that no matter which brush you kill, the brushes + will always break in a certain order. The order is set in the frags field. + The brush with a frags set to 1 will break first, brush with frags set to + 2 will break second, etc. + +OTHER FIELDS: +translucent - you can see through it +invincible - can't be shot and broken, but will break by linking +-------------------------FIELDS------------------------- +flag - order number +thingtype - type of chunks and sprites it will generate + 0 - glass (default) + 1 - grey stone + 2 - wood + 3 - metal + 4 - flesh + 5 - fire + 6 - clay + 7 - leaves + 8 - hay + 9 - brown stone + 10 - cloth + 11 - wood & leaf + 12 - wood & metal + 13 - wood stone + 14 - metal stone + 15 - metal cloth + 16 - spider web + 19 - clear glass + 20 - red glass + + 25 - DIRT! + +health - amount of damage item can take. Default is based on thingtype + glass - 25 + grey stone - 75 + wood - 50 + metal - 100 + flesh - 30 + fire - 999 + clay - 25 + leaves - 35 + hay - 35 + brown stone - 75 + cloth - 35 + wood&leaf - 35 + wood&metal - 75 + wood&stone - 65 + metal&stone - 90 + metal&cloth - 60 + others - 25 + +abslight - to set the absolute light level +pain_target - uses this target everytime the brush is hit + +-------------------------------------------------------- + +*/ +void breakable_brush() +{ + self.max_health = self.health; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + if (self.spawnflags & BREAK_ORDERED) + { + self.th_die = brush_use_ordered; + self.cnt = 1; + } + else if (self.spawnflags & BREAK_HIERARCH) + self.th_die = brush_use_hierarchy; + else + self.th_die = brush_use; + + if (self.spawnflags & BREAK_TRANSLUCENT) + self.drawflags(+)DRF_TRANSLUCENT; + + if(!self.thingtype) + self.thingtype=THINGTYPE_GLASS; + + if (!self.health) + if(self.thingtype<21) + self.health=breakhealth[self.thingtype]; + else + self.health = 50; + + self.max_health = self.health; + + if (self.flags) + self.frags = self.flags; + + if (self.abslight) + self.drawflags(+)MLS_ABSLIGHT; + + if (self.spawnflags&BREAK_INVINCIBLE) + self.takedamage = DAMAGE_NO; + else + self.takedamage = DAMAGE_YES; +// self.takedamage = DAMAGE_NO_GRENADE; + + if (self.spawnflags&BREAK_INVISIBLE) + { + self.effects (+) EF_NODRAW; + self.th_die = SUB_Remove; + } + else + self.th_die = chunk_death; + + if(self.spawnflags&BREAK_NOLINK) + self.use=self.th_die;//brush_no_link_use; + else + { + self.use = brush_use; + self.think=linkBreakables; + self.nextthink=self.ltime+0.1; + } + + if(self.pain_target!="") + self.th_pain = breakable_hurt_use; + + self.ltime = time; +} + diff --git a/bridge.hc b/bridge.hc new file mode 100644 index 0000000..09893be --- /dev/null +++ b/bridge.hc @@ -0,0 +1,215 @@ +/* + * $Header: /HexenWorld/Siege/Bridge.hc 3 5/25/98 1:38p Mgummelt $ + */ +/* +============================================================================== + +ROPE BRIDGES + +============================================================================== +*/ + + + + +/* + * Rope Bridge entity fields: + * ---------------------------- + * .owner - First link in this bridge. + * .count - Number of the last link in the bridge. + * .cnt - Number of this link. + * .movechain - Next link in the chain. Not used for last link. + * .dmg - Amount of stress being put on this link. + * .enemy - Last entity which was putting weight on this link. + * .speed - Distance this link will sway in the wind. + * .yaw_speed - Distance this link is from its origin cos of wind. + */ + + + + +/* + * ropebridge_touch() -- Affects the bridge when it's walked on. + */ + +void ropebridge_touch() +{ + local entity link; + local float difference; + + if(other.movetype != MOVETYPE_STEP && other.movetype != MOVETYPE_WALK) + return; + if(other == self.enemy) + return; + + link = self.owner.movechain; + self.enemy = other; + + while(link != self) // Links from start to self + { + link.dmg = link.dmg - link.cnt / self.cnt; + link = link.movechain; + } + + self.dmg = self.dmg + self.cnt; + difference = 1 / (self.count - self.cnt); + link = self.movechain; + + while(link.movechain) // Links from self to end + { + link.dmg = link.dmg - difference * (self.count - link.cnt); + link = link.movechain; + } + + link = self.owner.movechain; + while(link.movechain) + { + link.oldorigin_z = link.dmg; + setorigin(link, link.origin + link.oldorigin); + link = link.movechain; + } +} + + + +/* + * ropebridge_relieveweight() -- Relieves weight from touching monsters/players. + */ + +void ropebridge_relieveweight(entity focal) +{ + local entity link; + + link = self.owner.movechain; + + +} + + + +/* + * ropebridge_think() -- Sways the entire bridge a little. + */ + +void ropebridge_think() +{ + local entity link; + link = self.movechain; + + while(link.movechain) + { + if(link.enemy != world) + if(!EntitiesTouching(link, link.enemy)) + { + ropebridge_relieveweight(link); + link.enemy = world; + } + if(link.t_length) + setorigin(link, link.origin + (link.movedir * link.yaw_speed)); + else + setorigin(link, link.origin - (link.movedir * link.yaw_speed)); + if(link.t_width) + { + link.yaw_speed += 0.7; + if(link.yaw_speed >= link.speed) + { + link.t_width = 0; + link.yaw_speed = link.speed; + } + } + else { + link.yaw_speed -= 0.7; + if(link.yaw_speed < 0) + { + link.t_length = 0; + link.t_width = 1; + link.yaw_speed = 0; + } + } + link = link.movechain; + } + + self.nextthink = time + 0.05; +} + + +/* + * ropebridge_init() -- Sets up each link of the bridge. + * Only called by the first link. + */ + +void ropebridge_init() +{ + local entity link; + local float midpoint, thispoint; + + link = self; + + while(link.target) + { + if(link.classname != "ropebridge") + { + bprint("Error: Rope bridge link "); + bprint(ftos(self.count)); + bprint(" is targeted wrong\n"); + return; + } + link.owner = self; + link.movechain = find(world, targetname, link.target); + link.cnt = self.count; + link = link.movechain; + self.count = self.count + 1; + } + + link = self; + midpoint = self.count * 0.5; + thispoint = 1; + + while(thispoint <= self.count) + { + if(thispoint < midpoint) + link.speed = sqrt(thispoint - 1); + else + link.speed = sqrt(self.count - thispoint); + link.yaw_speed = link.speed; + link.count = self.count; + link = link.movechain; + thispoint = thispoint + 1; + } + + self.nextthink = time + 0.05; + self.think = ropebridge_think; +} + + + +/*QUAKED ropebridge_link (0.3 0.1 0.6) ? START +A link of a rope bridge which sways in the wind and drops a little when it's walked on. +-------------------------------------- +.target - The next link in the bridge. + Don't set if it's the last + link. +START - Check this if this is the + first link in the bridge. +-------------------------------------- +*/ + +void ropebridge_link() +{ + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + self.classname = "ropebridge"; + self.movedir = '0 1 -0.4'; + setmodel (self, self.model); + setorigin(self, self.origin); + + if(self.spawnflags) + { + self.count = 1; + self.nextthink = time + 0.05; + self.think = ropebridge_init; + } + else + self.touch = ropebridge_touch; +} + diff --git a/builtin.hc b/builtin.hc new file mode 100644 index 0000000..bc8643e --- /dev/null +++ b/builtin.hc @@ -0,0 +1,238 @@ + +//************************************************************************** +//** +//** builtin.hc +//** +//** $Header: /HexenWorld/Siege/builtin.hc 19 5/25/98 1:38p Mgummelt $ +//** +//************************************************************************** + +// Sets v_forward, etc. +void makevectors(vector ang) : 1; + +void setorigin(entity e, vector o) : 2; + +// Set movetype and solid before calling. +void setmodel(entity e, string m) : 3; + +void setsize(entity e, vector min, vector max) : 4; +void lightstylestatic(float style, float value) : 5; +void debugbreak(void) : 6; + +// Returns 0 - 1. +float random(void) : 7; + +void sound(entity e, float chan, string samp, float vol, float atten) : 8; +vector normalize(vector v) : 9; +void error(string e) : 10; +void objerror(string e) : 11; +float vlen(vector v) : 12; +float vectoyaw(vector v) : 13; +entity spawn(void) : 14; +void remove(entity e) : 15; + +// Sets trace_* globals. +void traceline(vector v1, vector v2, float nomonsters, + entity forent) : 16; + +// Returns a client to look for. +entity checkclient(void) : 17; + +entity find(entity start, .string fld, string match) : 18; + +// For sounds in demo and retail version. +string precache_sound(string s) : 19; + +// For models in demo and retail version. +string precache_model(string s) : 20; + +void stuffcmd(entity client, string s) : 21; +entity findradius(vector org, float rad) : 22; +void bprint(float level, string s) : 23; +void sprint(entity client, float level, string s) : 24; +void dprint(string s) : 25; +string ftos(float f) : 26; +string vtos(vector v) : 27; + +// Prints all edicts. +void coredump(void) : 28; + +void traceon(void) : 29; +void traceoff(void) : 30; + +// Prints an entire edict. +void eprint(entity e) : 31; + +// Returns TRUE or FALSE. +float walkmove (float yaw, float dist, float set_trace) : 32; + +float tracearea(vector v1, vector v2, vector mins, vector maxs, + float nomonsters, entity forent) : 33; + +// TRUE if landed on floor. +float droptofloor(void) : 34; + +void lightstyle(float style, string value) : 35; + +// Round to nearest int. +float rint(float v) : 36; + +// Largest integer <= v. +float floor(float v) : 37; + +// Smallest integer >= v. +float ceil(float v) : 38; + +// Award experience to player. +//void AwardExperience(entity ToEnt, entity FromEnt, float Amount) : 39; + +// TRUE if self is on ground. +float checkbottom(entity e) : 40; + +// Returns a CONTENT_*. +float pointcontents(vector v) : 41; + +// Start a particle effect. +void particle2(vector o, vector dmin, vector dmax, float color, + float type, float count) : 42; + +float fabs(float f) : 43; + +// Returns a shooting vector. +vector aim(entity e,vector d,float speed) : 44; + +// Returns the cvar value. +float cvar(string s) : 45; + +// Put a string into local que. +void localcmd(string s) : 46; + +// For looping through all ents. +entity nextent(entity e) : 47; + +// Start a particle effect. +void particle(vector o, vector d, float color, float count) : 48; + +// Turn towards self.ideal_yaw at self.yaw_speed. +float ChangeYaw(void) : 49; + +// Calculate distance, ignoring z. +float vhlen(vector v) : 50; + +vector vectoangles(vector v) : 51; + +void WriteByte(float to, float f) : 52; +void WriteChar(float to, float f) : 53; +void WriteShort(float to, float f) : 54; +void WriteLong(float to, float f) : 55; +void WriteCoord(float to, float f) : 56; +void WriteAngle(float to, float f) : 57; +void WriteString(float to, string s) : 58; +void WriteEntity(float to, entity s) : 59; +void dprintf(string s, float num) : 60; +float cos(float angle) : 61; +float sin(float angle) : 62; +float AdvanceFrame(float start, float end) : 63; +void dprintv(string s, vector vec) : 64; +float RewindFrame(float start, float end) : 65; + +void setclass(entity e, float value) : 66; + +void movetogoal(float step) : 67; + +// For files in demo and retail version. +string precache_file(string s) : 68; + +void makestatic(entity e) : 69; +void changelevel(string level, string spot) : 70; + +// Returns the current value of a light style. +float lightstylevalue(float style) : 71; + +// Sets a cvar value. +void cvar_set(string var, string val) : 72; + +// Same as sprint(), but centered. +void centerprint(entity client, string s) : 73; + +void ambientsound(vector pos, string samp, float vol, float atten) : 74; + +// For models only in retail version. +string precache_model2(string s) : 75; + +// For sounds only in retail version. +string precache_sound2(string s) : 76; + +// For files only in retail version. +string precache_file2(string s) : 77; + + +// Sets parm1... to the values at level start for coop respawn. +void setspawnparms(entity e) : 78; + +void plaque_draw(float to, float index) : 79; + +// Create rain. +void rain_go(vector v1, vector v2, vector e_size, vector dir, + float color, float count) : 80; + +// Particle explosion. +void particleexplosion(vector v,float f,float c,float s) : 81; + +// Move a step. +float movestep(float x, float y, float z, float set_trace) : 82; + +// Returns TRUE or FALSE (move other). +float advanceweaponframe(float startframe, float endframe) : 83; + +float sqrt(float num1) : 84; + +void particle3(vector o, vector box, float color, float type, float count) : 85; +void particle4(vector o, float radius, float color, float type, float count) : 86; + +// m will used as: models/puzzle/m.mdl +void setpuzzlemodel(entity e, string m) : 87; + +//float starteffect(float to, float effect) : 88; +float starteffect(...) : 88; +float endeffect(float to, float effect_id) : 89; + +string precache_puzzle_model(string s) : 90; +vector concatv(vector in, vector limit) : 91; +string getstring(float id) : 92; +entity spawn_temp(void) : 93; +vector v_factor(vector factor) : 94; + // returns (v_right * factor_x) + (v_forward * factor_y) + (v_up * factor_z) +vector v_factorrange(vector start, vector end) : 95; + +string precache_sound3(string s) : 96; +string precache_model3(string s) : 97; +string precache_file3(string s) : 98; + +void logfrag(entity killer, entity killee) : 99; // add to stats + +string infokey(entity e, string key) : 100; // get a key value (world = serverinfo) +float stof(string s) : 101; // convert string to float +void multicast(vector where, float set) : 102; // sends the temp message to a set +void turneffect(float effect_id, vector pos, vector dir) : 103; +void updateeffect(...) : 104; //have server send an update message (type-specific) to clients + // format: updateeffect(, , ); + +void setseed(float seed) : 105; //seed is really a short int +float seedrand(void) : 106; +void multieffect(...) : 107; +float getmeid(void) : 108; +void weapon_sound(entity e, string s) : 109; //net efficient weapon sound on entity +void bcenterprint2(string s, string s) : 110; // center prints two concated strings to all clients +void print_indexed(float to, float level, float index): 111;//print string in strings.txt indicated by index +void centerprint2(entity e, string s, string s) : 112; +void print_name(float to, float level, entity who) : 113;//print name of who + +void stopSound(entity e, float chan) : 114; +void updateSoundPos(entity e, float chan) : 115; + +string precache_sound5(string s) : 116; +string precache_model5(string s) : 117; +string precache_file5(string s) : 118; +void setsiegeteam(entity who, float s_team) : 119; +void updateSiegeInfo(void) : 120; diff --git a/buttons.hc b/buttons.hc new file mode 100644 index 0000000..3dd0fc2 --- /dev/null +++ b/buttons.hc @@ -0,0 +1,479 @@ +/* + * $Header: /HexenWorld/Siege/Buttons.hc 3 5/25/98 1:38p Mgummelt $ + */ +// button and multiple button + +float SPAWNFLAG_BUTTON_ACTIVATE = 1; +float FIRE_MULTIPLE = 4; + +void() button_wait; +void() button_return; +void() pressure_use; +void() pressure_touch; + +void() button_wait = +{ + self.state = STATE_TOP; + if(self.wait==-1) + if(!self.inactive) + self.nextthink=-1; + else + self.nextthink=self.ltime+0.3; + else + self.nextthink = self.ltime + self.wait; + self.think = button_return; + activator = self.enemy; + if (!self.inactive) + SUB_UseTargets(); + self.frame = 1; // use alternate textures +}; + +void() button_done = +{ + self.state = STATE_BOTTOM; +}; + +void() button_return = +{ + self.state = STATE_DOWN; + SUB_CalcMove (self.pos1, self.speed, button_done); + self.frame = 0; // use normal textures + if (self.health) + self.takedamage = DAMAGE_NO_GRENADE; // can be shot again +}; + +void() button_blocked = +{ // do nothing, just don't come all the way back out +}; + +void() button_fire = +{ + string s; + + if (self.inactive) + { + if (other.classname == "player" && self.msg2) + { + s = getstring(self.msg2); + centerprint(other, s); + } + return; + } + + if (self.state == STATE_UP) + return; + + self.check_ok = TRUE; + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + self.state = STATE_UP; + SUB_CalcMove (self.pos2, self.speed, button_wait); +}; + +void() button_use = +{ + self.enemy = activator; + button_fire (); +}; + +void() button_touch = +{ + if ((!other.flags&FL_PUSH)&&other.classname!="player") + return; + +// if(self.inactive) +// return; + + if (self.state == STATE_TOP) return; + + self.enemy = other; + button_fire (); +}; + +void() button_killed = +{ + self.enemy = damage_attacker; + self.health = self.max_health; + self.takedamage = DAMAGE_NO; // wil be reset upon return + button_fire (); +}; + +/*QUAKED func_button (0 .5 .8) ? deactivated FIREONLY FIRE_MULTIPLE x x x +When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again, +unless it's a pressure plate, in which case it will not return to it's position until it's not being touched anymore. +FIREONLY - has to be killed, touching won't do it. +FIRE_MULTIPLE - can be shot over and over (give it a high health) +-----------------------FIELDS------------------------- +"angle" determines the opening direction +"target" all entities with a matching targetname will be used +"speed" override the default 40 speed +"wait" override the default 1 second wait (-1 = never return) +"lip" override the default 4 pixel lip remaining at end of move +"health" if set, the button can be killed and touched +"abslight" - to set the absolute light level +"soundtype" +0) steam metal +1) wooden clunk +2) metallic click +3) in-out + +deactivated - button must be activated before it will work +-------------------------------------------------------- +*/ +void() func_button = +{ +// local float gtemp, ftemp; + + if (self.soundtype == 0) + { + precache_sound ("buttons/button1.wav"); + self.noise = "buttons/button1.wav"; + } + if (self.soundtype == 1) + { + precache_sound ("buttons/button2.wav"); + self.noise = "buttons/button2.wav"; + } + if (self.soundtype == 2) + { + precache_sound ("buttons/button3.wav"); + self.noise = "buttons/button3.wav"; + } + if (self.soundtype == 3) + { + precache_sound ("buttons/button4.wav"); + self.noise = "buttons/button4.wav"; + } + + SetMovedir (); + + if (self.abslight) + self.drawflags(+)MLS_ABSLIGHT; + + self.classname="button"; + self.movetype = MOVETYPE_PUSH; + self.solid = SOLID_BSP; + setmodel (self, self.model); + + self.blocked = button_blocked; + self.use = button_use; + + if (self.health) + { + self.max_health = self.health; + if(self.spawnflags&FIRE_MULTIPLE) + self.th_pain = button_use;//for multiple uses + self.th_die = button_killed; + self.takedamage = DAMAGE_NO_GRENADE; + } + + if (!self.spawnflags & 2) + { + if (!self.health) self.health = 10; + self.touch = button_touch; + } + + if (!self.speed) + self.speed = 40; + if (!self.wait) + self.wait = 1; + if (!self.lip) + self.lip = 4; + + //If activatable, set usable flags off + if(self.spawnflags&SPAWNFLAG_BUTTON_ACTIVATE) + self.inactive=TRUE; + else self.inactive=FALSE; + + self.state = STATE_BOTTOM; + + self.pos1 = self.origin; + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + + self.ltime = time; +}; + +/* +------------------------------------------------------------------------- +*/ +float pressure_weight_check () +{ +vector org; +float len, totalmass; +entity head; + org = (self.absmax + self.absmin)*0.5; + len = vlen(self.absmax - self.absmin)*0.66; + + head = findradius(org, len); + + while (head) + { + if(head!=self) + { + if(head.flags2&FL_ALIVE) + totalmass += head.mass*10; + else + totalmass += head.mass; +/* if(head.netname) + dprint(head.netname); + else + dprint(head.classname); + dprint(" weight added\n"); +*/ } + head = head.chain; + } + +/* dprint("Measured mass: "); + dprint(ftos(totalmass)); + dprint("\n"); + dprint("Required mass: "); + dprint(ftos(self.mass)); + dprint("\n"); +*/ + if (totalmass >= self.mass) + return TRUE; + else + return FALSE; +} + +float pressure_bounds_check () +{ +vector org1,org2,org3,org4, center,found_bottom; +float radius; +entity found; + + org1_z=org2_z=org3_z=org4_z=self.absmax_z+3; + org1_x = self.absmin_x; + org1_y = self.absmin_y; + + org2_x = self.absmin_x; + org2_y = self.absmax_y; + + org3_x = self.absmax_x; + org3_y = self.absmin_y; + + org4_x = self.absmax_x; + org4_y = self.absmax_y; + + center=(self.absmax+self.absmin)*0.5; + center_z=self.absmax_z; + radius=fabs(self.absmax_x-center_x); + + found=findradius(center,radius); + while(found) + { + found_bottom=(found.absmin+found.absmax)*0.5; + found_bottom_z=found.absmin_z; + if(found!=self) + if(found_bottom_x>self.absmin_x&&found_bottom_xself.absmin_y&&found_bottom_y=self.absmax_z - 3&&found_bottom_z<=self.absmax_z+7) + return TRUE; + else + dprint("Not right height\n"); + else + dprint("Not right y\n"); + else + dprint("Not right x\n"); + found=found.chain; + } + return FALSE; +} + +void() pressure_wait = +{ +float tripped; + tripped=TRUE; + if(!pressure_bounds_check()) + tripped=FALSE; + + if (!pressure_weight_check()) + tripped=FALSE; + + if(tripped) + { + self.check_ok = TRUE; + self.nextthink = self.ltime + 0.05; + } + else + { + self.check_ok = FALSE; + pressure_use(); + + self.touch = pressure_touch; + SUB_CalcMove(self.pos1, self.speed, SUB_Null); + } +}; + +void() pressure_fire = +{ + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + self.state = STATE_UP; + self.touch = SUB_Null; + + SUB_UseTargets(); + + SUB_CalcMove (self.pos2, self.speed, pressure_wait); +}; + +void() pressure_use = +{ + self.enemy = activator; + pressure_fire (); +}; + +void() pressure_touch = +{ + if(other==world) + return; + +entity found; +float inbounds,enough_weight; + + if(pressure_bounds_check()) + inbounds=TRUE; + + if (pressure_weight_check()) + enough_weight=TRUE; + + if(inbounds) + { + if(enough_weight) + { + self.check_ok = TRUE; + self.touch = SUB_Null; + pressure_use(); + } + else + { + if(self.pain_finishedself.level) + self.cnt-=1; + + makevectors(self.owner.v_angle); + viewdir=normalize(v_forward); + spot1=self.owner.origin+self.owner.proj_ofs+'0 0 6'; + spot2=spot1-viewdir*self.cnt; + traceline(spot1,spot2,TRUE,self.owner); + + viewdir=normalize(spot1-trace_endpos); + setorigin(self,trace_endpos+viewdir*4); + + self.think=CameraThink; + thinktime self : 0; +} + +void ToggleChaseCam (entity voyeur) +{ + if(voyeur.viewentity.classname=="chasecam") + { +//Turn off camera view + CameraViewPort(voyeur,voyeur); + CameraViewAngles(voyeur,voyeur); + remove(voyeur.viewentity); + voyeur.viewentity=voyeur; + voyeur.view_ofs=voyeur.proj_ofs+'0 0 6'; + voyeur.attack_finished=0; + voyeur.weaponmodel=voyeur.lastweapon; + voyeur.oldweapon=FALSE; + W_SetCurrentAmmo(); + } + else + { + if(voyeur.cameramode!=voyeur&&voyeur.cameramode!=world) + centerprint(voyeur,"Chase camera not available while in another camera mode\n"); + + voyeur.lastweapon=voyeur.weaponmodel; + voyeur.oldweapon=0; + voyeur.weaponmodel=""; + makevectors(voyeur.v_angle); + voyeur.viewentity=spawn(); + voyeur.viewentity.owner=voyeur; + voyeur.viewentity.angles=voyeur.angles; + voyeur.viewentity.level=cvar("chase_back"); + if(!voyeur.viewentity.level) + voyeur.viewentity.level=68; + voyeur.viewentity.cnt=4; + voyeur.viewentity.classname="chasecam"; + voyeur.view_ofs='0 0 0'; + + setmodel(voyeur.viewentity,"models/null.spr"); + setsize(voyeur.viewentity, '0 0 0','0 0 0'); + setorigin(voyeur.viewentity,voyeur.origin+voyeur.proj_ofs+'0 0 6'-v_forward*4); + + CameraViewPort(voyeur,voyeur.viewentity); + CameraViewAngles(voyeur,voyeur.viewentity); + + voyeur.viewentity.think=CameraThink; + thinktime voyeur.viewentity : 0; + } +} + diff --git a/cameramg.hc b/cameramg.hc new file mode 100644 index 0000000..be79cac --- /dev/null +++ b/cameramg.hc @@ -0,0 +1,83 @@ +void(entity voyeur, entity viewthing) CameraViewPort = +{//FIXME: Doesn't seem to work if it's out of vis- only +// remembers last spot it was at last time it WAS in vis + msg_entity = voyeur; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity (MSG_ONE, viewthing); +}; + +void(entity voyeur, entity viewthing) CameraViewAngles = +{//FIXME: Doesn't seem to work if it's out of vis- only +// remembers last angles it was at last time it WAS in vis + msg_entity = voyeur; + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + if(viewthing.classname=="camera_remote") + WriteAngle(MSG_ONE, 360-viewthing.angles_x); + else + WriteAngle(MSG_ONE, viewthing.angles_x); + WriteAngle(MSG_ONE, viewthing.angles_y); + WriteAngle(MSG_ONE, viewthing.angles_z); +}; + +void CameraThink () +{ +vector viewdir; +vector spot1,spot2; + self.level=cvar("chase_back"); + if(self.cntself.level) + self.cnt-=1; + + makevectors(self.owner.v_angle); + viewdir=normalize(v_forward); + spot1=self.owner.origin+self.owner.proj_ofs+'0 0 6'; + spot2=spot1-viewdir*self.cnt; + traceline(spot1,spot2,TRUE,self.owner); + + viewdir=normalize(spot1-trace_endpos); + setorigin(self,trace_endpos+viewdir*4); + + self.think=CameraThink; + thinktime self : 0; +} + +void MakeCamera () +{ + if(self.viewentity.classname=="chasecam") + { +//Turn off camera view + CameraViewPort(self,self); + CameraViewAngles(self,self); + self.attack_finished=0; + W_SetCurrentAmmo(); + remove(self.viewentity); + self.viewentity=self; + self.view_ofs=self.proj_ofs+'0 0 6'; + } + else + { + self.lastweapon=self.weaponmodel; + self.weaponmodel=""; + makevectors(self.v_angle); + self.viewentity=spawn(); + self.viewentity.owner=self; + self.viewentity.angles=self.angles; + self.viewentity.level=cvar("chase_back"); + if(!self.viewentity.level) + self.viewentity.level=68; + self.viewentity.cnt=4; + self.viewentity.classname="chasecam"; + self.view_ofs='0 0 0'; + + setmodel(self.viewentity,"models/null.spr"); + setsize(self.viewentity, '0 0 0','0 0 0'); + setorigin(self.viewentity,self.origin+self.proj_ofs+'0 0 6'-v_forward*4); + + CameraViewPort(self,self.viewentity); + CameraViewAngles(self,self.viewentity); + + self.viewentity.think=CameraThink; + thinktime self.viewentity : 0; + } +} diff --git a/cat2.hc b/cat2.hc new file mode 100644 index 0000000..25b2051 --- /dev/null +++ b/cat2.hc @@ -0,0 +1,411 @@ +/*QUAKED obj_catapult2 (0 .5 .8) (-150 -150 0) (150 150 28) ? + +"speed" Throw speed (300 default) +"wait" wait before resetting (3 default) +"health" Just how tough is it (defaults to 1000) +"mass" How hard is it to push (defaults to 1000) +"thingtype" Defaults to THINGTYPE_WOOD +"aflag" - Max distance it can be pushed from start pos (default 256) + "-1" disables this +"sounds" +0) no sound +1) stone +2) base +3) stone chain +4) screechy metal + +*/ + +void catapult_ready (void) +{ +//FIXME: No linking in touch, do it all in here with a tracearea (is that working?) and findradius +// if(self.flags&FL_ONGROUND&&world.model!="maps/siege3.bsp") +// self.movetype = MOVETYPE_NONE; + + if(self.origin!=self.oldorigin||self.angles!=self.o_angle) + { + entity found; + vector dir,org,fmins,fmaxs; +// dprint("updating dependancies\n"); + makevectors(self.angles); + dir=normalize(v_forward); + org=self.origin+dir*-4*self.level; + org_z=self.absmax_z; + found=nextent(world); + while(found) + { + //Find ground entity + fmins=found.mins; + fmaxs=found.maxs; + fmins_z=0; + fmaxs_z=8; + tracearea(found.origin+'0 0 1',found.origin-'0 0 8',fmins,fmaxs,FALSE,found); + if(trace_ent!=self) + found.catapulter=world; + if(vhlen(found.origin-org)<2*self.level&&found.catapulter==self) + { + float repos_dist,repos_dist_cnt,repos_dir_angle; + vector repos_dir; + entity save_ent; +// dprint(found.classname); +// dprint(" updated\n"); + repos_dir=org+found.pos_ofs - found.origin; + repos_dist=vlen(repos_dir); + repos_dir=normalize(repos_dir); + repos_dir_angle=vectoyaw(repos_dir); + save_ent=self; + self=found; + while(repos_dist_cntself.o_angle_y) + AdvanceFrame(33,42); + else if(self.angles_y=20) + { + sound(self,CHAN_VOICE,"misc/catreset.wav",1,ATTN_NORM); + self.frame=20; + self.think=catapult_ready; + thinktime self : 0; + } + else + { + self.frame+=1; + self.think=catapult_reset; + thinktime self : 0.05; + } +}; + +void catapult_wait (void) +{ +entity firstcat, catdude; + firstcat=catdude=find(world,classname,other.catapulter.classname); + while(catdude) + { + if(other.catapulter==self) + other.catapulter=world; + catdude=find(catdude,classname,other.catapulter.classname); + if(catdude==firstcat) + catdude=world; + } + + self.think=catapult_reset; + thinktime self : self.wait; +} + +void catapult_fire (void) +{ + if(self.frame==20||self.frame>22) + { + sound(self,CHAN_VOICE,"misc/catlnch.wav",1,ATTN_NORM); + entity found; + vector dir,org,addvel; + float distance, force,centrifugal,throwback; + found=nextent(world); + makevectors(self.angles); + dir=normalize(v_forward); + org=self.origin+dir*-4*self.level; + org_z=self.absmax_z; + + while(found) + { + distance=vhlen(found.origin-org); + +// if(found.catapulter==self) + + if(distance<2*self.level&&found.origin_z>self.origin_z+self.maxs_z*0.75)//&&found.catapulter==self) + { +// inertia? + + found.catapult_time=time+3; + found.catapulter=world; + + traceline(found.origin,found.origin-'0 0 33',FALSE,found); + if(trace_ent!=self) + {//off back edge, throw backwards + throwback=TRUE; + centrifugal=vhlen(found.origin-org); + force=self.speed + random(-100,100) + centrifugal*4;//Ignore mass, Not exact physics, but feels better + addvel=dir*-1*force+v_right*random(-50,50);//Give some left-right innacuracy to it + force=self.speed + random(-100,100)+ centrifugal*4; + addvel_z=force; + } + else + { + throwback=FALSE; + centrifugal=vhlen(found.origin-self.origin); + force=self.speed + random(-100,100) + centrifugal*4;//4 Ignore mass, Not exact physics, but feels better + addvel=dir*force+v_right*random(-50,50);//Give some left-right innacuracy to it + force=self.speed + random(-100,100)+ centrifugal*4; + addvel_z=force;//FIXME: CAP at ??? + } +// if(found.playerclass==CLASS_DWARF) +// addvel*=1.05; + found.velocity+=addvel; + if(!found.touch) + found.touch=obj_push; + found.flags(-)FL_ONGROUND; + if(found.classname=="player"&&found.playerclass!=CLASS_SUCCUBUS) + { + found.teleport_time=time+1.7;//No mario + } + if(!found.flags2&FL_ALIVE) + { + found.velocity=found.velocity*1.3; + if(throwback) + found.avelocity=found.velocity*(48-centrifugal)*random(-1,1); + else + found.avelocity=found.velocity*random(-1,1); + found.movetype=MOVETYPE_BOUNCE; + } + + if(found.model=="models/sheep.mdl") + { + if(found.classname!="player") + { + found.velocity=found.velocity*1.3; + found.teleport_time+=666;//impact damage forever + found.touch=found.th_die; + found.enemy = self.enemy; + if(found.trigger_field) + remove(found.trigger_field); + } + found.avelocity=found.velocity*random(-1,1); + found.movetype=MOVETYPE_BOUNCE; + sound(found,CHAN_VOICE,"misc/sheepfly.wav",1,ATTN_NORM); + found.pain_finished=time+1; + } + if(found.model=="models/barrel.mdl") + { + found.touch = found.th_die;//Maybe make them always explode on touch + if(found.netname=="obj_barrel_gfire") + sound(self,CHAN_BODY,"misc/gflaunch.wav",1,ATTN_NORM); + + if(found.trigger_field) + remove(found.trigger_field); + found.enemy = self.enemy; + found.think = found.th_die; + thinktime found : 5; + } + } + + found=nextent(found); + } + } + if(self.frame>=22) + { + self.frame=22; + self.think=catapult_wait; + thinktime self : 0; + } + else + { + self.frame+=1; + self.think=catapult_fire; + thinktime self : 0.05; + } +} + +void catapult_pain (void) +{ + if(!self.enemy.flags2&FL_ALIVE&&self.enemy.classname!="blood missile") + return; + + if(self.frame==20||self.frame>22) + catapult_fire(); +} + +void catapult2_touch(void) +{ + if(other.solid==SOLID_BSP||other==self.movechain||other==world) + return; + +/* dprint(other.classname); + dprint("\n"); + dprint(ftos(other.absmin_z)); + dprint(" > "); + dprint(ftos(self.absmax_z)); + dprint("?\n");*/ + + if(other.origin_z-(other.mins_z*0.75)>=self.origin_z+(self.maxs_z*0.75)) + { + if(other.solid!=SOLID_TRIGGER&&other.movetype&&other.catapulter!=self&&other.catapult_time100||coop||deathmatch)&&other.flags&FL_ONGROUND&&(other.impulse==13||self.last_use_time + 2>time)) + {//only players can directly push it +// Push or spin + vector dir1, dir2,move_vel,dest_spot; + float magnitude,dot_forward,inertia;//,dot_right; + if(other.impulse == 13) + self.last_use_time = time; + self.angles_x=self.angles_z=0; + makevectors(self.angles); + magnitude=400;//vlen(other.velocity); + inertia=1/(self.mass/10); + + dir1=normalize(self.origin-other.origin); + dir2=normalize(v_forward); + dir1_z=dir2_z=0; + + dot_forward= dir1*dir2; + + if(dot_forward >0.8) + { + move_vel=dir2*magnitude*inertia*5; + dest_spot=self.origin+(move_vel*0.01); + if(self.aflag!=-1) + if(vhlen(dest_spot-self.wallspot)>=self.aflag) + return; +// walkmove(self.angles_y,1,FALSE); + // dprint("Move forward\n"); + self.velocity=move_vel;//FIXME: adds up if do += (for multiple pushers) +// dprint(vtos(self.velocity)); + self.flags(-)FL_ONGROUND; + AdvanceFrame(23,32); + } + else if(dot_forward<-0.8) + { + move_vel=dir2*-1*magnitude*inertia*5; + dest_spot=self.origin+(move_vel*0.01); + if(self.aflag!=-1) + if(vhlen(dest_spot-self.wallspot)>=self.aflag) + return; +// dprint("Move backwards\n"); +// walkmove(self.angles_y,-1,FALSE); + self.velocity=move_vel;//FIXME: adds up if do += (for multiple pushers) + self.flags(-)FL_ONGROUND; + AdvanceFrame(32,23); + } +// if(self.movechain) +// setorigin(self.movechain,self.origin+'0 0 26'); +/* else + { + dir1=normalize(other.velocity); + dir2=normalize(v_right); + dot_right= dir1*dir2; + if(dot_right >0.2) + { + if(dot_forward >0.2) + { + self.angles_y-=1*magnitude/100; + } + else if(dot_forward<-0.2) + { + self.angles_y+=1*magnitude/100; + } + } + else if(dot_right<-0.2) + { + if(dot_forward >0.2) + { + self.angles_y+=1*magnitude/100; + } + else if(dot_forward<-0.2) + { + self.angles_y-=1*magnitude/100; + } + } + }*/ + } + +} + +void obj_catapult2 (void) +{ + precache_model("models/cattest.mdl"); + precache_sound ("misc/catlnch.wav"); + precache_sound ("misc/catreset.wav"); + precache_sound ("misc/catdrop.wav"); + + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_PUSHPULL; + self.touch=catapult2_touch; +// setmodel (self, "models/catapult.mdl"); + setmodel (self, "models/cattest.mdl"); + setsize(self,'-145 -145 0','145 145 26'); + self.hull=HULL_SCORPION; + setorigin (self, self.origin); + self.wallspot=self.origin; + if(self.aflag==0) + self.aflag=256;//Max dist to move from origin- not working? Set to movetyp NONE if gets too far? then can;t turn... + self.classname="catapult"; + self.level = 30; + self.frame=20; + + self.th_pain=catapult_pain; + self.th_weapon=catapult_fire; + + if (!self.speed) + self.speed = 300;//Too strong? + if (self.wait==0) + self.wait = 3; + self.th_die = chunk_death; + self.takedamage = DAMAGE_YES; + self.use=catapult_fire; + + if(!self.thingtype) + self.thingtype = THINGTYPE_WOOD; + + if(!self.mass) + self.mass = 1000; + + if (!self.health) + self.health=1000; + + self.max_health = self.health = self.health*2; + + self.think=catapult_ready; + thinktime self : 0; + + spawn_push_trigger(10); +} + diff --git a/catapult.hc b/catapult.hc new file mode 100644 index 0000000..eaf1982 --- /dev/null +++ b/catapult.hc @@ -0,0 +1,89 @@ +void movechain_target (void) +{ + if(self.target) + { + entity found; + found=find(world,targetname,self.target); + if(found==self) + { + found=nextent(self); + found=find(found,targetname,self.target); + } + self.movechain=found; + found.flags(+)FL_MOVECHAIN_ANGLE; + } + else + { + dprint(self.classname); + dprint(" has no target set\n"); + } + self.nextthink=-1; +} + +void BSP_stop (void) +{ + self.velocity='0 0 0'; + self.think=BSP_stop; + self.nextthink=time - 1; +} + +void BSP_push (void) +{ +vector pos,dir; + if(other.absmin_z>self.absmin_z+4||vlen(other.velocity)<150) + return; + dir=normalize(other.velocity+self.velocity); + dir_z=0; + pos=dir*10+self.origin; + SUB_CalcMove(pos,10,BSP_stop); +} + +/*QUAKED obj_stairs (0 .5 .8) ? +*/ +void obj_stairs (void) +{ + if(!self.thingtype) + self.thingtype=THINGTYPE_WOOD; + if(self.health) + { + self.takedamage=DAMAGE_NO_GRENADE; + self.th_die=chunk_death; + } + + self.flags(+)FL_PUSH; + self.solid=SOLID_BSP; + self.movetype=MOVETYPE_PUSH; + self.touch=BSP_push; + + setmodel (self, self.model); + setsize(self,self.mins,self.maxs); + setorigin(self,self.origin); +} + +/*QUAKED obj_bridge (0 .5 .8) ? +*/ +void obj_bridge (void) +{ + if(!self.thingtype) + self.thingtype=THINGTYPE_WOOD; + if(self.health) + { + self.takedamage=DAMAGE_NO_GRENADE; + self.th_die=chunk_death; + } + + self.solid=SOLID_SLIDEBOX; + self.movetype=MOVETYPE_PUSHPULL; + self.touch=obj_push; + + setmodel (self, self.model); + setsize(self,self.mins,self.maxs); + setorigin(self,self.origin); +} +void() catapult_button_turn= +{ +}; +void() catapult_button_think= +{ +}; + diff --git a/chunk.hc b/chunk.hc new file mode 100644 index 0000000..21f56d0 --- /dev/null +++ b/chunk.hc @@ -0,0 +1,662 @@ +/* + * $Header: /HexenWorld/Siege/chunk.hc 10 5/25/98 1:38p Mgummelt $ + */ +void ThrowSolidHead (float dm); + +void blood_splatter() +{ + SpawnPuff(self.origin,normalize(self.velocity)*-20,10,self); + remove(self); +} + +void ThrowBlood (vector org,vector dir) +{ +entity blood; + blood=spawn_temp(); + blood.solid=SOLID_BBOX; + blood.movetype=MOVETYPE_TOSS; + blood.touch=blood_splatter; + blood.velocity=dir; + blood.avelocity=randomv('-700 -700 -700','700 700 700'); + blood.thingtype=THINGTYPE_FLESH; + + setmodel(blood,"models/bldspot4.spr"); // 8 x 8 sprite size + setsize(blood,'0 0 0','0 0 0'); + setorigin(blood,org); +} + +void ZeBrains (vector spot, vector normal, float scaling, float face, float roll) +{ + newmis=spawn(); + newmis.scale=scaling; + newmis.angles=vectoangles(normal); + if(face) + newmis.angles_y+=180; + newmis.angles_z=roll; + + setmodel(newmis,"models/brains.mdl"); + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,spot+normal*1); + + newmis.think=corpseblink; + thinktime newmis : 30; + + spot=newmis.origin; + makevectors(normal); + ThrowBlood(spot,(normal+random(0.75,0.75)*v_up+random(0.75,0.75)*v_right)*random(200,400)); + ThrowBlood(spot,(normal+random(0.75,0.75)*v_up+random(0.75,0.75)*v_right)*random(200,400)); + ThrowBlood(spot,(normal+random(0.75,0.75)*v_up+random(0.75,0.75)*v_right)*random(200,400)); + ThrowBlood(spot,(normal+random(0.75,0.75)*v_up+random(0.75,0.75)*v_right)*random(200,400)); + ThrowBlood(spot,(normal+random(0.75,0.75)*v_up+random(0.75,0.75)*v_right)*random(200,400)); +} + +void ChunkRemove (void) +{ + chunk_cnt-=1; + SUB_Remove (); +} + +vector ChunkVelocity (void) +{ + local vector v; + + v_x = 300 * crandom(); + v_y = 300 * crandom(); + v_z = random(100,400); + + v = v * 0.7; + + return v; +} + +void ThrowSingleChunk (string chunkname,vector location,float life_time,float skinnum) +{ + entity chunk; + + if (chunk_cnt < CHUNK_MAX) + { + chunk=spawn_temp(); + setmodel (chunk, chunkname); + chunk.frame = 0; + + setsize (chunk, '0 0 0', '0 0 0'); + chunk.movetype = MOVETYPE_BOUNCE; + chunk.solid = SOLID_NOT; + chunk.takedamage = DAMAGE_NO; + chunk.velocity = ChunkVelocity(); + chunk.think = ChunkRemove; + chunk.flags(-)FL_ONGROUND; + chunk.origin = location; + + chunk.avelocity_x = random(10); + chunk.avelocity_y = random(10); + chunk.avelocity_z = random(30); + chunk.skin = skinnum; + chunk.ltime = time; + thinktime chunk : life_time; + chunk_cnt+=1; + } +} + + +void MeatChunks (vector org,vector dir,float chunk_count,entity loser) +{ +float final; +entity chunk; + + while(chunk_count) + { + chunk=spawn_temp(); + chunk_count-=1; + final = random(); + + if(loser.model=="models/spider.mdl") + { + if (final < 0.33) + setmodel (chunk, "models/sflesh1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/sflesh2.mdl"); + else + setmodel (chunk, "models/sflesh3.mdl"); + } + else if (final < 0.33) + setmodel (chunk, "models/flesh1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/flesh2.mdl"); + else + setmodel (chunk, "models/flesh3.mdl"); + setsize (chunk, '0 0 0', '0 0 0'); +// chunk.skin=1; + chunk.movetype = MOVETYPE_BOUNCE; + chunk.solid = SOLID_NOT; + if(dir=='0 0 0') + chunk.velocity = ChunkVelocity(); + else + chunk.velocity=dir;//+randomv('-200 -200 -200','200 200 200'); + chunk.think = ChunkRemove; + chunk.avelocity_x = random(1200); + chunk.avelocity_y = random(1200); + chunk.avelocity_z = random(1200); + + chunk.scale = .45; + + chunk.ltime = time; + thinktime chunk : random(2); + setorigin (chunk, org); + } +} + +void CreateModelChunks (vector space,float scalemod) +{ + entity chunk; + float final; + + chunk = spawn_temp(); + + space_x = space_x * random(); + space_y = space_y * random(); + space_z = space_z * random(); + + setorigin (chunk, self.absmin + space); + + final = random(); + if ((self.thingtype==THINGTYPE_GLASS) || (self.thingtype==THINGTYPE_REDGLASS) || + (self.thingtype==THINGTYPE_CLEARGLASS) || (self.thingtype==THINGTYPE_WEBS)) + { + if (final<0.20) + setmodel (chunk, "models/shard1.mdl"); + else if (final<0.40) + setmodel (chunk, "models/shard2.mdl"); + else if (final<0.60) + setmodel (chunk, "models/shard3.mdl"); + else if (final<0.80) + setmodel (chunk, "models/shard4.mdl"); + else + setmodel (chunk, "models/shard5.mdl"); + + if (self.thingtype==THINGTYPE_CLEARGLASS) + { + chunk.skin=1; + chunk.drawflags (+) DRF_TRANSLUCENT; + } + else if (self.thingtype==THINGTYPE_REDGLASS) + chunk.skin=2; + else if (self.thingtype==THINGTYPE_WEBS) + { + chunk.skin=3; +// chunk.drawflags (+) DRF_TRANSLUCENT; + } + } + else if (self.thingtype==THINGTYPE_WOOD) + { + if (final < 0.25) + setmodel (chunk, "models/splnter1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/splnter2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/splnter3.mdl"); + else + setmodel (chunk, "models/splnter4.mdl"); + } + else if (self.thingtype==THINGTYPE_METAL) + { + if (final < 0.25) + setmodel (chunk, "models/metlchk1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/metlchk2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/metlchk3.mdl"); + else + setmodel (chunk, "models/metlchk4.mdl"); + } + else if (self.thingtype==THINGTYPE_FLESH) + { + if(self.model=="models/spider.mdl") + { + if (final < 0.33) + setmodel (chunk, "models/sflesh1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/sflesh2.mdl"); + else + setmodel (chunk, "models/sflesh3.mdl"); + } + else if (final < 0.33) + setmodel (chunk, "models/flesh1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/flesh2.mdl"); + else + setmodel (chunk, "models/flesh3.mdl"); + if(self.classname=="hive") + chunk.skin=1; + } + else if (self.thingtype==THINGTYPE_BROWNSTONE||self.thingtype==THINGTYPE_DIRT) + { + if (final < 0.25) + setmodel (chunk, "models/schunk1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/schunk2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/schunk3.mdl"); + else + setmodel (chunk, "models/schunk4.mdl"); + chunk.skin = 1; + } + else if (self.thingtype==THINGTYPE_CLAY) + { + if (final < 0.25) + setmodel (chunk, "models/clshard1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/clshard2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/clshard3.mdl"); + else + setmodel (chunk, "models/clshard4.mdl"); + } + else if (self.thingtype==THINGTYPE_LEAVES) + { + if (final < 0.33) + setmodel (chunk, "models/leafchk1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/leafchk2.mdl"); + else + setmodel (chunk, "models/leafchk3.mdl"); + } + else if (self.thingtype==THINGTYPE_HAY) + { + if (final < 0.33) + setmodel (chunk, "models/hay1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/hay2.mdl"); + else + setmodel (chunk, "models/hay3.mdl"); + } + else if (self.thingtype==THINGTYPE_CLOTH) + { + if (final < 0.33) + setmodel (chunk, "models/clthchk1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/clthchk2.mdl"); + else + setmodel (chunk, "models/clthchk3.mdl"); + } + else if (self.thingtype==THINGTYPE_WOOD_LEAF) + { + if (final < 0.14) + setmodel (chunk, "models/splnter1.mdl"); + else if (final < 0.28) + setmodel (chunk, "models/leafchk1.mdl"); + else if (final < 0.42) + setmodel (chunk, "models/splnter2.mdl"); + else if (final < 0.56) + setmodel (chunk, "models/leafchk2.mdl"); + else if (final < 0.70) + setmodel (chunk, "models/splnter3.mdl"); + else if (final < 0.84) + setmodel (chunk, "models/leafchk3.mdl"); + else + setmodel (chunk, "models/splnter4.mdl"); + } + else if (self.thingtype==THINGTYPE_WOOD_METAL) + { + if (final < 0.125) + setmodel (chunk, "models/splnter1.mdl"); + else if (final < 0.25) + setmodel (chunk, "models/metlchk1.mdl"); + else if (final < 0.375) + setmodel (chunk, "models/splnter2.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/metlchk2.mdl"); + else if (final < 0.625) + setmodel (chunk, "models/splnter3.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/metlchk3.mdl"); + else if (final < 0.875) + setmodel (chunk, "models/splnter4.mdl"); + else + setmodel (chunk, "models/metlchk4.mdl"); + } + else if (self.thingtype==THINGTYPE_WOOD_STONE) + { + if (final < 0.125) + setmodel (chunk, "models/splnter1.mdl"); + else if (final < 0.25) + setmodel (chunk, "models/schunk1.mdl"); + else if (final < 0.375) + setmodel (chunk, "models/splnter2.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/schunk2.mdl"); + else if (final < 0.625) + setmodel (chunk, "models/splnter3.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/schunk3.mdl"); + else if (final < 0.875) + setmodel (chunk, "models/splnter4.mdl"); + else + setmodel (chunk, "models/schunk4.mdl"); + } + else if (self.thingtype==THINGTYPE_METAL_STONE) + { + if (final < 0.125) + setmodel (chunk, "models/metlchk1.mdl"); + else if (final < 0.25) + setmodel (chunk, "models/schunk1.mdl"); + else if (final < 0.375) + setmodel (chunk, "models/metlchk2.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/schunk2.mdl"); + else if (final < 0.625) + setmodel (chunk, "models/metlchk3.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/schunk3.mdl"); + else if (final < 0.875) + setmodel (chunk, "models/metlchk4.mdl"); + else + setmodel (chunk, "models/schunk4.mdl"); + } + else if (self.thingtype==THINGTYPE_METAL_CLOTH) + { + if (final < 0.14) + setmodel (chunk, "models/metlchk1.mdl"); + else if (final < 0.28) + setmodel (chunk, "models/clthchk1.mdl"); + else if (final < 0.42) + setmodel (chunk, "models/metlchk2.mdl"); + else if (final < 0.56) + setmodel (chunk, "models/clthchk2.mdl"); + else if (final < 0.70) + setmodel (chunk, "models/metlchk3.mdl"); + else if (final < 0.84) + setmodel (chunk, "models/clthchk3.mdl"); + else + setmodel (chunk, "models/metlchk4.mdl"); + } + else if (self.thingtype==THINGTYPE_ICE) + { + setmodel(chunk,"models/shard.mdl"); + chunk.skin=0; + chunk.frame=random(2); + chunk.drawflags(+)DRF_TRANSLUCENT|MLS_ABSLIGHT; + chunk.abslight=0.5; + } + else// if (self.thingtype==THINGTYPE_GREYSTONE) + { + if (final < 0.25) + setmodel (chunk, "models/schunk1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/schunk2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/schunk3.mdl"); + else + setmodel (chunk, "models/schunk4.mdl"); + chunk.skin = 0; + } + + setsize (chunk, '0 0 0', '0 0 0'); + chunk.movetype = MOVETYPE_BOUNCE; + chunk.solid = SOLID_NOT; + chunk.velocity = ChunkVelocity(); + chunk.think = ChunkRemove; + chunk.avelocity_x = random(1200); + chunk.avelocity_y = random(1200); + chunk.avelocity_z = random(1200); + + if(self.classname=="monster_eidolon") + chunk.scale=random(2.1,2.5); + else + chunk.scale = random(scalemod,scalemod + .1); + + chunk.ltime = time; + thinktime chunk : random(2); +} + +void DropBackpack(void); // in items.hc + + +// Put a little splat down if it will fit +void TinySplat (vector location) +{ + vector holdplane; + entity splat; + + traceline (location + v_up*8 + v_right * 8 + v_forward * 8,location - v_up*32 + v_right * 8 + v_forward * 8, TRUE, self); + holdplane = trace_plane_normal; + if(trace_fraction==1) // Nothing below victim + return; + + traceline (location + v_up*8 - v_right * 8 + v_forward * 8,location - v_up*32 - v_right * 8 + v_forward * 8, TRUE, self); + if ((holdplane != trace_plane_normal) || (trace_fraction==1)) + return; + + traceline (location + v_up*8 + v_right * 8 - v_forward * 8,location - v_up*32 + v_right * 8 - v_forward * 8, TRUE, self); + if ((holdplane != trace_plane_normal) || (trace_fraction==1)) + return; + + traceline (location + v_up*8 - v_right * 8 - v_forward * 8,location - v_up*32 - v_right * 8 - v_forward * 8, TRUE, self); + if ((holdplane != trace_plane_normal) || (trace_fraction==1)) + return; + + traceline (location + v_up*8 ,location - v_up*32 , TRUE, self); + + splat=spawn(); + splat.owner=self; + splat.classname="bloodsplat"; + splat.movetype=MOVETYPE_NONE; + splat.solid=SOLID_NOT; + + // Flat to the surface + trace_plane_normal_x = trace_plane_normal_x * -1; + trace_plane_normal_y = trace_plane_normal_y * -1; + splat.angles = vectoangles(trace_plane_normal); + + setmodel(splat,"models/bldspot4.spr"); // 8 x 8 sprite + setsize(splat,'0 0 0','0 0 0'); + setorigin(splat,trace_endpos + '0 0 2'); + +} + +void BloodSplat(void) +{ + entity splat; + vector holdangles; + + if (random() < .5) + { + holdangles_x = random(-30,-20); + holdangles_y = random(30,20); + } + else + { + holdangles_x = random(30,20); + holdangles_y = random(-30,-20); + } + + holdangles_z = 16; + TinySplat (self.origin + holdangles); + + if (random() < .5) + { + holdangles_x = random(-30,-10); + holdangles_y = random(30,10); + } + else + { + holdangles_x = random(30,10); + holdangles_y = random(-30,-10); + } + + holdangles_z = 16; + TinySplat (self.origin + holdangles); + + makevectors (self.angles); + + traceline (self.origin + v_up*8,self.origin - v_up*32, TRUE, self); + + if(trace_fraction==1) // Nothing below victim + { + dprint("\n no floor "); + return; + } + + splat=spawn(); + splat.owner=self; + splat.classname="bloodsplat"; + splat.movetype=MOVETYPE_NONE; + splat.solid=SOLID_NOT; + + // Flat to the surface + trace_plane_normal_x = trace_plane_normal_x * -1; + trace_plane_normal_y = trace_plane_normal_y * -1; + splat.angles = vectoangles(trace_plane_normal); + +// setmodel(splat,"models/bldspot1.spr"); // 30 x 30 sprite size + setmodel(splat,"models/bldspot2.spr"); // 20 x 20 sprite size +// setmodel(splat,"models/bldspot3.spr"); // 18 x 18 sprite size +// setmodel(splat,"models/bldspot4.spr"); // 8 x 8 sprite size + setsize(splat,'0 0 0','0 0 0'); + setorigin(splat,trace_endpos + '0 0 2'); + +} + +void chunk_reset () +{ + chunk_cnt=FALSE; + remove(self); +} + +void make_chunk_reset () +{ + newmis=spawn(); + newmis.think=chunk_reset; + thinktime newmis : 1.5; +} + +void chunk_death (void) +{ + vector space; + float spacecube,model_cnt; //,scalemod; + string deathsound; + + DropBackpack(); + +// BloodSplat(); + + space = self.absmax - self.absmin; + + spacecube = space_x * space_y * space_z; + + model_cnt = spacecube / 8192; // (16 * 16 * 16) + + if ((self.thingtype==THINGTYPE_GLASS) || (self.thingtype==THINGTYPE_CLEARGLASS) || (self.thingtype==THINGTYPE_REDGLASS)) + deathsound="fx/glassbrk.wav"; + else if ((self.thingtype==THINGTYPE_WOOD) || (self.thingtype==THINGTYPE_WOOD_METAL)) + if(self.classname=="bolt") + deathsound="assassin/arrowbrk.wav"; + else + deathsound="fx/woodbrk.wav"; + else if ((self.thingtype==THINGTYPE_GREYSTONE) || (self.thingtype==THINGTYPE_BROWNSTONE) || + (self.thingtype==THINGTYPE_WOOD_STONE) || (self.thingtype==THINGTYPE_METAL_STONE)||self.thingtype==THINGTYPE_DIRT) + deathsound="fx/wallbrk.wav"; + else if ((self.thingtype==THINGTYPE_METAL) || (self.thingtype==THINGTYPE_METAL_CLOTH)) + deathsound="fx/metalbrk.wav"; + else if ((self.thingtype==THINGTYPE_CLOTH) || (self.thingtype==THINGTYPE_REDGLASS)) + deathsound="fx/clothbrk.wav"; + else if (self.thingtype==THINGTYPE_FLESH) + { + //Made temporary changes to make weapons look and sound + //better, more blood and gory sounds. + if(self.health<-80) + deathsound="player/megagib.wav"; + else + deathsound="player/gib1.wav"; + sound(self,CHAN_AUTO,deathsound,1,ATTN_NORM); + self.level=-666; + } + else if (self.thingtype==THINGTYPE_CLAY) + deathsound="fx/claybrk.wav"; + else if ((self.thingtype==THINGTYPE_LEAVES) || (self.thingtype==THINGTYPE_WOOD_LEAF)) + deathsound="fx/leafbrk.wav"; + else if (self.thingtype==THINGTYPE_ICE) + deathsound="misc/icestatx.wav"; + else + deathsound="fx/wallbrk.wav"; + + if(self.level!=-666) + sound (self, CHAN_VOICE, deathsound, 1, ATTN_NORM); + // Scale 0 - 50,000 small + // 50,000 - 500,000 medium + // 500,000 large + // 1,000,000 + huge +/* if (spacecube < 5000) + { + scalemod = .20; + model_cnt = model_cnt * 3; // Because so few pieces come out of a small object + } + else if (spacecube < 50000) + { + scalemod = .45; + model_cnt = model_cnt * 3; // Because so few pieces come out of a small object + } + else if (spacecube < 500000) + { + scalemod = .50; + } + else if (spacecube < 1000000) + { + scalemod = .75; + } + else + { + scalemod = 1; + } + + if(model_cnt>CHUNK_MAX) + model_cnt=CHUNK_MAX; + + while (model_cnt>0) + { + if (chunk_cnt < CHUNK_MAX*2) + { + CreateModelChunks(space,scalemod); + chunk_cnt+=1; + } + + model_cnt-=1; + } +*/ + make_chunk_reset(); + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_CHUNK2); + WriteCoord(MSG_MULTICAST, self.absmin_x); + WriteCoord(MSG_MULTICAST, self.absmin_y); + WriteCoord(MSG_MULTICAST, self.absmin_z); + WriteCoord(MSG_MULTICAST, space_x); + WriteCoord(MSG_MULTICAST, space_y); + WriteCoord(MSG_MULTICAST, space_z); + WriteByte(MSG_MULTICAST, self.thingtype); + multicast(self.absmin+0.5*space,MULTICAST_PHS_R); + + if(self.classname=="monster_eidolon") + return; + + SUB_UseTargets(); + +// if(self.classname=="door"||self.classname=="door_rotating") + if(self.ondeath_target!="") + { + string otarg; + otarg = self.target; + self.target=self.ondeath_target; + SUB_UseTargets(); + self.target=otarg; + dprint("Door using it's ondeath target\n"); + } + + if(self.trigger_field) + remove(self.trigger_field); + + if(self.headmodel!=""&&self.classname!="head") + ThrowSolidHead (50); + else + remove(self); +} + diff --git a/client.hc b/client.hc new file mode 100644 index 0000000..2d8ff9a --- /dev/null +++ b/client.hc @@ -0,0 +1,3511 @@ +/* + * $Header: /HexenWorld/Siege/Client.hc 77 6/01/98 5:45p Mgummelt $ + */ + +// prototypes +void () W_WeaponFrame; +void() W_SetCurrentAmmo; +void (vector org, entity death_owner, float alive_only_tf) spawn_tdeath; +void() DecrementSuperHealth; +void CheckRings (void); + + +void FreezeAllEntities(void) +{ + entity search; + + search = nextent(world); + while(search != world) + { + if (search.classname != "player") + { + thinktime search : 99999; + } + search = nextent(search); + } +} + +/* +============================================================================= + + LEVEL CHANGING / INTERMISSION + +============================================================================= +*/ + +float intermission_running; +float intermission_exittime; + +/*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16) +This is the camera point for the intermission. Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw' +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void info_intermission(void) +{ +} + +/* +============ +FindIntermission + +Returns the entity to view from +============ +*/ +entity FindIntermission(void) +{ +entity spot; +float cyc; + +// look for info_intermission first + spot = find (world, classname, "info_intermission"); + if (spot) + { // pick a random one + cyc = random(4); + while (cyc > 1) + { + spot = find (spot, classname, "info_intermission"); + if (!spot) + spot = find (spot, classname, "info_intermission"); + cyc = cyc - 1; + } + return spot; + } + +// then look for the start position + spot = find (world, classname, "info_player_start"); + if (spot) + return spot; + +// testinfo_player_start is only found in regioned levels + spot = find (world, classname, "testplayerstart"); + if (spot) + return spot; + + objerror ("FindIntermission: no spot"); +} + + +string nextmap; +string nextstartspot; + +void GotoNextMap(void) +{ + if (cvar("samelevel")) // if samelevel is set, stay on same level + { + changelevel (mapname, startspot); + } + else + { + changelevel (nextmap, nextstartspot); + } +} + + +void ExitIntermission(void) +{ + // skip any text in deathmatch + if (deathmatch) + { + intermission_exittime = + intermission_running = 0; + } + + other = find (world, classname, "player"); + while (other != world) + { + stuffcmd(other, "-showdm\n"); + other.frags=0;//reset frags + other.takedamage = DAMAGE_YES; + other.solid = SOLID_BBOX; + other.movetype = MOVETYPE_WALK; + other.flags(-)FL_NOTARGET; + other.effects=FALSE; + other.skin = other.siege_team = 0; + setsiegeteam(other, 0); + other.weaponmodel=other.lastweapon; + other = find (other, classname, "player"); + } + + if (deathmatch) + { + gameover = FALSE; + GotoNextMap (); + return; + } + + intermission_exittime = time + 1; + intermission_running = intermission_running + 1; + + // + // run some text if at the end of an episode + // + + if (intermission_running == 2) + GotoNextMap(); +} + +/* +============ +IntermissionThink + +When the player presses attack or jump, change to the next level +============ +*/ +void IntermissionThink(void) +{ + if (time < intermission_exittime) +// { +// string printnum; +// printnum = ftos(floor(intermission_exittime - time)); +// centerprint_all_clients(printnum); + return; +// } + + if (!self.button0 && !self.button1 && !self.button2) + return; + + ExitIntermission (); +} + +void() execute_changelevel = +{ + intermission_running = 1; + +// enforce a wait time before allowing changelevel + + if(dmMode==DM_SIEGE) + intermission_exittime = time + 30; + else if (deathmatch) + intermission_exittime = time + 5; + else + intermission_exittime = time + 2; + + + other = find (world, classname, "player"); + while (other != world) + { +// other.sv_flags=serverflags; + thinktime other : 0.5; + other.takedamage = DAMAGE_NO; + other.solid = SOLID_NOT; + other.movetype = MOVETYPE_NONE; + other.flags(+)FL_NOTARGET; +// other.effects=EF_NODRAW|EF_LIGHT; + other.lastweapon=other.weaponmodel; + stuffcmd(other,"+showdm\n"); + other = find (other, classname, "player"); + } +}; + +/* +void FindDMLevel(void) +{ + serverflags (+) SFL_NEW_UNIT; + + nextmap = string_null; + + if (cvar("registered") != 0 || cvar("oem") != 0) + { + if (mapname == "demo1") + nextmap = "demo2"; + else if (mapname == "demo2") + nextmap = "demo3"; + else if (mapname == "demo3") + nextmap = "village1"; + else if (mapname == "village1") + nextmap = "village2"; + else if (mapname == "village2") + nextmap = "village3"; + else if (mapname == "village3") + nextmap = "village4"; + else if (mapname == "village4") + nextmap = "village5"; + else if (mapname == "village5") + nextmap = "rider1a"; + else if (mapname == "rider1a") + nextmap = "demo1"; + + else if (mapname == "meso1") + nextmap = "meso2"; + else if (mapname == "meso2") + nextmap = "meso3"; + else if (mapname == "meso3") + nextmap = "meso4"; + else if (mapname == "meso4") + nextmap = "meso5"; + else if (mapname == "meso5") + nextmap = "meso6"; + else if (mapname == "meso6") + nextmap = "meso8"; + else if (mapname == "meso8") + nextmap = "meso9"; + else if (mapname == "meso9") + nextmap = "meso1"; + + else if (mapname == "egypt1") + nextmap = "egypt2"; + else if (mapname == "egypt2") + nextmap = "egypt3"; + else if (mapname == "egypt3") + nextmap = "egypt4"; + else if (mapname == "egypt4") + nextmap = "egypt5"; + else if (mapname == "egypt5") + nextmap = "egypt6"; + else if (mapname == "egypt6") + nextmap = "egypt7"; + else if (mapname == "egypt7") + nextmap = "rider2c"; + else if (mapname == "rider2c") + nextmap = "egypt1"; + + else if (mapname == "romeric1") + nextmap = "romeric2"; + else if (mapname == "romeric2") + nextmap = "romeric3"; + else if (mapname == "romeric3") + nextmap = "romeric4"; + else if (mapname == "romeric4") + nextmap = "romeric5"; + else if (mapname == "romeric5") + nextmap = "romeric6"; + else if (mapname == "romeric6") + nextmap = "romeric7"; + else if (mapname == "romeric7") + nextmap = "romeric1"; + + else if (mapname == "cath") + nextmap = "tower"; + else if (mapname == "tower") + nextmap = "castle4"; + else if (mapname == "castle4") + nextmap = "castle5"; + else if (mapname == "castle5") + nextmap = "eidolon"; + else if (mapname == "eidolon") + nextmap = "cath"; + + else if (mapname == "ravdm1") + nextmap = "ravdm2"; + else if (mapname == "ravdm2") + nextmap = "ravdm3"; + else if (mapname == "ravdm3") + nextmap = "ravdm4"; + else if (mapname == "ravdm4") + nextmap = "ravdm5"; + else if (mapname == "ravdm5") + nextmap = "hwdm1"; + else if (mapname == "hwdm1") + nextmap = "hwdm2"; + else if (mapname == "hwdm2") + nextmap = "hwdm3"; + else if (mapname == "hwdm3") + nextmap = "hwdm4"; + else if (mapname == "hwdm4") + nextmap = "hwdm5"; + else if (mapname == "hwdm5") + nextmap = "ravdm1"; + } + else + { + if (mapname == "demo1") + nextmap = "demo2"; + else if (mapname == "demo2") + nextmap = "ravdm1"; + else if (mapname == "ravdm1") + nextmap = "demo1"; + } +} +*/ + +void() changelevel_touch = +{ + + if (other.classname != "player")//||(!infront_of_ent(self,other))) + return; + + if ((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start"))) + { +// rjr quake2 change T_Damage (other, self, self, 50000, 1000, TRUE); + T_Damage (other, self, self, 50000); + return; + } + + if (self.movedir != '0 0 0') + { + makevectors (other.angles); + if (v_forward * self.movedir < 0) + return; // not facing the right way + } + + //FIXME: temp server flags fix +// other.sv_flags=serverflags; + if (coop || deathmatch) + { + bprintname (PRINT_MEDIUM, other); + bprinti (PRINT_MEDIUM, STR_EXITEDLEVEL); + } + + if (deathmatch) + FindDMLevel(); + else + { + nextmap = self.map; + nextstartspot = self.target; + } + + SUB_UseTargets (); + + if (cvar("registered") == 0 && cvar("oem") == 0 && nextmap == "village1") + { + remove(self); + intermission_running = 2; + intermission_exittime = time + 20; + WriteByte (MSG_ALL, SVC_INTERMISSION); + WriteByte (MSG_ALL, 5); + FreezeAllEntities(); + return; + } + +/* if (self.spawnflags & 2) + { + serverflags (+) SFL_NEW_UNIT; + serverflags (-) SFL_CROSS_TRIGGERS; + } + else + serverflags (-) SFL_NEW_UNIT; + if (self.spawnflags & 4) + { + serverflags (+) SFL_NEW_EPISODE; + serverflags (-) SFL_CROSS_TRIGGERS; + } + else + serverflags (-) SFL_NEW_EPISODE; */ + +// rjr spawnflag 1 use to be "no intermission" - removed the option completely +// if ( (self.spawnflags & 1) && (deathmatch == 0) ) + + if ( (deathmatch == 0) ) + { // NO_INTERMISSION + GotoNextMap(); + return; + } + + self.touch = SUB_Null; + +// we can't move people right now, because touch functions are called +// in the middle of C movement code, so set a think time to do it + self.think = execute_changelevel; + thinktime self : 0.1; +}; + +void() changelevel_use = +{ + local entity saveOther; + + saveOther = other; + other = activator; + changelevel_touch (); + other = saveOther; +}; + +/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? x END_OF_UNIT END_OF_EPISODE +When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. +*/ +void() trigger_changelevel = +{ + if (!self.map) + objerror ("changelevel trigger doesn't have map"); + + InitTrigger (); + self.touch = changelevel_touch; + self.use = changelevel_use; +}; + + +/* +============================================================================= + + PLAYER GAME EDGE FUNCTIONS + +============================================================================= +*/ + +//void() set_suicide_frame; +void(vector dir)GibPlayer; +// called by ClientKill and DeadThink +void() respawn = +{ + if (coop) + { + // make a copy of the dead body for appearances sake + SolidPlayer(); + // get the spawn parms as they were at level start + setspawnparms (self); + // respawn + + PutClientInServer (); + } + else if (deathmatch) + { + // make a copy of the dead body for appearances sake + SolidPlayer(); + PutClientInServer (); + } + else + { // restart the entire server + if(parm7) + changelevel (mapname, startspot); + else + localcmd ("restart restore\n"); + } +}; + + +/* +============ +ClientKill + +Player entered the suicide command +============ +*/ +void() ClientKill = +{ +//entity lastleader,newking; + if(dmMode==DM_SIEGE&&gamestarted&&self.siege_team) + { + centerprint(self,"Can't suicide in Siege once game is begun!\n");// Minimum jail sentence is 3 minutes!\n"); + return; +// if(self.jail_time>time) +// { +// centerprint(self,"Can't suicide- Minimum jail sentence is 3 minutes!\n"); +// return; +// } + } + if(self.flags2&FL2_EXCALIBUR) + WriteTeam (SVC_NODOC,self); + + if (self.last_use_time < time - 10) + { + bprintname (PRINT_MEDIUM, self); + bprinti (PRINT_MEDIUM, STR_SUICIDES); + self.model=self.init_model; + PlayerDie(5000,'0 0 1'); + if(self.puzzle_inv1!="") + { + self.puzzle_id=self.puzzle_inv1; + DropPuzzlePiece(); + self.puzzle_inv1=self.puzzle_id=""; + } + self.frags -= 2; // extra penalty + drop_level(self,2); + respawn (); + self.last_use_time = time; + } +}; + +void go_up () +{ + if(self.level>=1000) + remove(self); + else + { + setorigin(self,self.origin+'0 0 25'); + self.level+=25; + self.think = go_up; + thinktime self : 0.05; + } +} + +void go_smear () +{ + self.cnt+=1; + self.think=go_smear; + thinktime self : 0.05; + if(self.cnt<10) + self.angles_y+=random(2,10); + else if(self.cnt<30) + self.angles_y-=random(2,10); + else if(self.cnt<50) + self.angles_y+=random(2,10); + else if(self.cnt<70) + self.angles_y-=random(2,10); + else if(self.cnt<80) + self.angles_y+=random(2,10); + else + go_up(); +} + +void go_smite () +{ + if(!self.level) + go_smear(); + else if(self.level==50) + { + self.enemy.deathtype="smitten"; + T_Damage(self.enemy,self,self,10000); + traceline(self.enemy.origin, self.enemy.origin - '0 0 128', TRUE, self); + if (trace_fraction < 1&&!trace_ent.flags2&FL_ALIVE&&trace_ent.solid==SOLID_BSP) + ZeBrains(trace_endpos, trace_plane_normal, random(1.3,2), rint(random(1)),random(360)); + setorigin(self,self.enemy.origin+'0 0 1'*self.level); + self.level-=25; + self.think = go_smite; + thinktime self : 0.05; + } + else + { + setorigin(self,self.enemy.origin+'0 0 1'*self.level); + self.level-=25; + self.think = go_smite; + thinktime self : 0.05; + } +} + +void FingerOfGod () +{ +entity finger; + finger=spawn(); + finger.classname="Finger Of God"; + setmodel(finger,"models/god.mdl"); + finger.enemy=self; + setorigin(finger,self.origin+'0 0 1000'); + finger.level=1000; + finger.think=go_smite; + finger.effects = EF_BRIGHTLIGHT; + sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,"misc/smite.wav",1,ATTN_NONE); + thinktime finger : 0; +} + +void() SmitePlayer =//server doesn't like you! +{ + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte(MSG_MULTICAST, TE_LIGHTNING_HAMMER); + WriteEntity(MSG_MULTICAST, self); + multicast(self.origin,MULTICAST_PVS); + FingerOfGod(); +}; + +float(vector v) CheckSpawnPoint = +{ + return FALSE; +}; + +/* +============ +SelectSpawnPoint + +Returns the entity to spawn at +============ +*/ +//@@ TODO: not fixed order!!! +entity() SelectSpawnPoint = +{//FIXME: if start on 2nd - 5th hubs, fill in correct startspot string + entity spot; +// entity bestspot; + entity thing;//, firstthing; + float pcount; + float ok; +// float bestdist, curdist, curclosest; +// float dmsearch,tsearch; + +// testinfo_player_start is only found in regioned levels + spot = find (world, classname, "testplayerstart"); + if (spot) + return spot; + +//QuickClassChange + if(self.newclass) + { + spot = find(world, classname, "classchangespot"); + if(spot) + { + spot.think=SUB_Remove; + thinktime spot : 1; + return spot; + } + } + +//Totally changed spot selection for Siege + string spotname; + spot = lastspawn; + pcount = 1; + if(self.siege_team==ST_DEFENDER) + spotname = "info_player_defender"; + else if(self.siege_team==ST_ATTACKER) + spotname = "info_player_attacker"; + else + spotname = "info_player_deathmatch"; + + while (pcount > 0 && pcount < 3) + {//search three times for right spot + spot = find(spot, classname, spotname); + if (spot) + { + thing = findradius(spot.origin, 64); + ok = TRUE; + while (thing) + { + if (thing.classname == "player") + { + thing = world; + ok = FALSE; + } + else + thing = thing.chain; + } + if (ok) + { + lastspawn = spot; + return lastspawn; + } + } + if (spot == world) + pcount += 1; + } +//Uh-oh, didn't find one! + if (spot == world) + return world; + +}; + +/* +=========== +PutClientInServer + +called each time a player is spawned +============ +*/ +void(float damage, vector dir) PlayerDie; + +void() PutClientInServer = +{ +entity spot; +float alive_only_tf; + + spot = SelectSpawnPoint (); + if(!spot) + {//try again in 1/2 a second + dprint("Error! All start spots are blocked!!!\n"); + self.think=PutClientInServer; + thinktime self : 0.5; + return; + } + if(spot.classname=="classchangespot") + alive_only_tf=TRUE;//Telefrag living stuff only + + if(deathmatch) + { + if(!altRespawn||dmMode==DM_SIEGE) + { + self.items(-)IT_WEAPON4|IT_WEAPON3|IT_WEAPON4_1|IT_WEAPON4_2|IT_WEAPON2; + } + self.skin=GLOBAL_SKIN_NOTEAM; + } +// else if(self.sv_flags) +// serverflags=self.sv_flags; + + stuffcmd(self,"color 0 0\n"); + self.fov_val=90; + self.climbing=FALSE; + self.climbspot='0 0 0'; + self.last_climb=0; + self.classname = "player"; + self.takedamage = DAMAGE_YES; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_WALK; + self.deathtype=""; + self.viewentity=self; + self.wallspot='0 0 0'; + self.scale=1; + self.skin=GLOBAL_SKIN_NOTEAM; + self.drawflags=self.abslight=self.effects=0; + self.flags(+)FL_CLIENT; + self.flags2(+)FL_ALIVE; + self.flags2(-)FL2_WALLCLIMB; + self.air_finished = time + 12; + self.dmg = 2; // initial water damage + self.thingtype=THINGTYPE_FLESH; + self.adjust_velocity = '-999 -999 -999'; +//Reset all time-based fields + self.act_state = + self.show_hostile = + self.onfire= + self.invisible_time= + self.camptime= + self.last_attack= + self.torchtime= + self.healthtime= + self.catapult_time= + self.safe_time= + self.absorb_time= + self.last_impact= + self.sheep_sound_time= + self.still_time= + self.last_onground= + self.invisible_finished= + self.invincible_time= + self.splash_time= + self.ring_regen_time= + self.rings_low= + self.pausetime = + self.teleport_time = + self.sheep_time = + self.attack_finished = + self.super_damage_time= + self.haste_time = + self.tome_time = + self.camera_time= + self.ring_regen_time= + self.ring_flight_time= + self.ring_water_time= + self.ring_turning_time= + self.super_damage= + self.super_damage_low= + self.hasted= + self.decap= + self.frozen= + self.plaqueflg = 0; + self.artifact_active(-)ARTFLAG_FROZEN|ARTFLAG_STONED; + self.gameFlags (-) GF_HAS_TOKEN; + self.effects (-) EF_BRIGHTFIELD;//Hey! I set effects to "0" above... + self.raven_cnt = 0; + self.friction=self.gravity=self.standard_grav = 1; + + self.last_use_time = self.last_time = time; + + if(tomeMode == 2) + { + self.poweredFlags = 0; + } + + if (self.has_portals == 0 && self.next_playerclass == CLASS_SUCCUBUS) + { + self.next_playerclass = CLASS_NONE; + } + if (self.has_portals == 0 && self.newclass == CLASS_SUCCUBUS) + { + self.newclass = CLASS_NONE; + } + + if (self.playerclass != self.next_playerclass) + { + self.playerclass = self.next_playerclass; + if (self.playerclass) + { + setclass(self, self.playerclass); + stats_NewClass(self); + } + } + + if(self.newclass) + { + bprintname(PRINT_MEDIUM, self); + bprint(PRINT_MEDIUM, " becomes a "); + if(self.newclass==CLASS_PALADIN) + bprint(PRINT_MEDIUM, "Paladin!\n"); + else if(self.newclass==CLASS_CRUSADER) + bprint(PRINT_MEDIUM, "Crusader!\n"); + else if(self.newclass==CLASS_NECROMANCER) + bprint(PRINT_MEDIUM, "Necromancer!\n"); + else if(self.newclass==CLASS_ASSASSIN) + bprint(PRINT_MEDIUM, "Assassin!\n"); + else if(self.newclass==CLASS_DWARF) + bprint(PRINT_MEDIUM, "Dwarf!\n"); + else + bprint(PRINT_MEDIUM, "Succubus!\n"); + self.playerclass=self.newclass; + setclass(self,self.playerclass); + stats_NewClass(self); + self.newclass=FALSE; + } + + if(deathmatch&&randomclass) + self.playerclass=CLASS_NONE; + + if (self.playerclass == CLASS_NONE) + { // Default it to the paladin if not selected + if (cvar("oem")) + { + setclass(self,rint(random(1,4))); + } + else if (cvar("registered") != 0 && self.has_portals) + { + setclass(self,rint(random(1,5))); + } + else if (cvar("registered") != 0) + { + setclass(self,rint(random(1,4))); + } + else + { + if (random() < 0.5) + setclass(self,CLASS_PALADIN); + else + setclass(self,CLASS_ASSASSIN); + } + stats_NewClass(self); + } + +// if(fixedLevel) +// { +// PlayerAdvanceLevel(fixedLevel); +// } + +// bprint(PRINT_MEDIUM, "Health is "); +// bprint(PRINT_MEDIUM, ftos(self.health)); +// bprint(PRINT_MEDIUM, "\n"); + + if(self.max_health<=0)// || deathmatch) + { +// if(!fixedLevel) +// { + self.strength = 0; + self.siege_team=0; + //this may crash, don't do this for now? + setsiegeteam(self, 0); + stats_NewPlayer(self); +// } + } + else + self.health = self.max_health; + + if(self.max_health<=0||self.health<=0)//just in case + self.health=self.max_health=100; + + self.deadflag = DEAD_NO; + + setorigin(self, spot.origin + '0 0 1'); + self.angles = spot.angles; + self.fixangle = TRUE; // turn this way immediately + + if(!self.weapon) + { + self.items=IT_WEAPON1; + self.weapon=IT_WEAPON1; + self.oldweapon=IT_WEAPON1; + } + if(deathmatch) + self.weapon=IT_WEAPON1; + + if(coop) + {//Need more mana in coop, especially if you die + if(self.bluemana<25) + self.bluemana=25; + if(self.greenmana<25) + self.greenmana=25; + } + + W_SetCurrentAmmo (); + + SetModelAndThinks(); + + if(self.siege_team) + self.skin=self.siege_team - 1; + else + self.skin=GLOBAL_SKIN_NOTEAM; + + if(deathmatch) + { + self.effects=0; + self.artifact_active=ART_INVINCIBILITY; + self.invincible_time = time + 3; + self.artifact_low(+)ART_INVINCIBILITY; + + if(self.playerclass==CLASS_CRUSADER||self.playerclass==CLASS_DWARF) + { + self.oldskin=self.skin; + self.skin = GLOBAL_SKIN_STONE; + } + else if(self.playerclass==CLASS_PALADIN) + self.effects(+)EF_BRIGHTLIGHT; + else if(self.playerclass==CLASS_ASSASSIN) + self.colormap=140; + else if(self.playerclass==CLASS_NECROMANCER) + self.effects(+)EF_DARKLIGHT; + else + { + self.drawflags(+)MLS_ABSLIGHT; + self.effects(+)EF_INVINC_CIRC; + self.abslight=0.75; + } + } + self.ring_regen_time = 0; + self.ring_flight_time=0; + self.ring_water_time=0; + self.ring_turning_time=0; + + self.ring_flight=0; // Health of rings 0 - 100 + self.ring_water=0; // + self.ring_turning=0; // + self.ring_regeneration=0; // + self.rings = 0; + + if(self.playerclass!=CLASS_DWARF) + { + self.view_ofs = '0 0 50'; + self.proj_ofs=' 0 0 44'; + self.hull=HULL_PLAYER; + } + else + { + self.view_ofs = '0 0 26'; + self.proj_ofs=' 0 0 20'; + self.hull=HULL_CROUCH; + } + + self.idealpitch = cvar("sv_walkpitch"); + + if(dmMode==DM_SIEGE) + self.greenmana=self.bluemana=0; + + PlayerSpeed_Calc(self); + + self.button0 = self.button1 = self.button2 = 0; + self.attack_finished=time+0.5;//so no respawn fire + +// self.th_stand(); + player_frames(); + + if (deathmatch || coop) + { + makevectors(self.angles); + GenerateTeleportEffect(self.origin,0); + } + + spawn_tdeath (self.origin, self, alive_only_tf); + + if(tomeRespawn) + { + self.cnt_tome += 1; + Use_TomeofPower(); + self.tome_time = time + 15; + } + if(w2Respawn&&dmMode!=DM_SIEGE) + { + self.items(+)IT_WEAPON2; + if(self.bluemana<25) + { + self.bluemana=25; + } + } + + if(self.items & (IT_WEAPON2|IT_WEAPON3|IT_WEAPON4)) + { + if(self.items & IT_WEAPON4) + { + self.weapon = IT_WEAPON4; + } + else if(self.items & IT_WEAPON3) + { + self.weapon = IT_WEAPON3; + } + else + { + self.weapon = IT_WEAPON2; + } + self.oldweapon = IT_WEAPON1; + + W_SetCurrentAmmo (); + + SetModelAndThinks(); + } + + if (START_LIT) + self.effects(+)EF_DIMLIGHT; + + updateSiegeInfo(); + self.bluemana=self.greenmana=0; +}; + + +void ClientReEnter(float TimeDiff) +{ +/* + Called for living players entering a level + (except for first starting a game) + or when you die any time other than on the + first level you started playing on. +*/ +entity spot; +//string tempmodel; + + if(!self.flags2&FL_ALIVE||self.health<1||(self.newclass&&!deathmatch&&!coop)) + {//If dead, put them in the right spot. + self.weapon=IT_WEAPON1; + PutClientInServer(); + return; + } + + // Need to reset these because they could still point to entities in the previous map + self.enemy = self.groundentity = self.chain = self.goalentity = self.dmg_inflictor = + self.owner = world; + +//RESET TIMERS: + if(deathmatch) + { + self.items(-)IT_WEAPON4|IT_WEAPON2|IT_WEAPON3|IT_WEAPON4_1|IT_WEAPON4_2; + self.skin=GLOBAL_SKIN_NOTEAM; + } +// else if(self.sv_flags) +// serverflags=self.sv_flags; + + self.fov_val=90; + self.movetype=MOVETYPE_WALK; + self.viewentity=self; + self.wallspot='0 0 0'; + self.deathtype=""; + self.act_state = + self.onfire= + self.healthtime= + self.splash_time= + self.decap= + self.frozen= + self.plaqueflg = 0; + self.raven_cnt = 0; + self.friction=self.gravity=self.standard_grav = 1; + self.artifact_active(-)ARTFLAG_FROZEN|ARTFLAG_STONED; + + self.ring_flight_time = 0; + self.ring_flight = 0; + self.rings (-) RING_FLIGHT; + self.rings_active (-) RING_FLIGHT; + + self.air_finished = time + 12; + + self.ring_regen_time += TimeDiff; + self.ring_water_time += TimeDiff; + self.ring_turning_time += TimeDiff; + + self.super_damage_time += TimeDiff; + self.haste_time += TimeDiff; + self.tome_time += TimeDiff; + self.camera_time += TimeDiff; + self.torchtime += TimeDiff; + + self.pausetime += TimeDiff; + self.teleport_time += TimeDiff; + self.sheep_time += TimeDiff; + self.attack_finished += TimeDiff; + self.catapult_time+= TimeDiff; + self.safe_time+= TimeDiff; + self.absorb_time+= TimeDiff; + self.last_impact+= TimeDiff; + self.sheep_sound_time+= TimeDiff; + self.still_time+= TimeDiff; + self.last_onground+= TimeDiff; + self.invincible_time+= TimeDiff; + self.show_hostile+= TimeDiff; + self.invisible_time+= TimeDiff; + self.camptime+= TimeDiff; + self.last_attack= self.attack_finished=0; + + self.last_time = time; + + self.light_level = 128; // So the assassin doesn't go invisible coming out of the teleporter + + self.dmg = 2; // initial water damage + + if(self.playerclass!=CLASS_DWARF) + { + setsize (self, '-16 -16 0', '16 16 56'); + self.hull=HULL_PLAYER; + self.view_ofs = '0 0 50'; + self.proj_ofs='0 0 44'; + } + else + { + setsize (self, '-16 -16 0', '16 16 28'); + self.hull=HULL_CROUCH; + self.view_ofs = '0 0 26'; + self.proj_ofs='0 0 20'; + } + + spot = SelectSpawnPoint (); + setorigin(self, spot.origin + '0 0 1'); + self.angles = spot.angles; + self.fixangle = TRUE; // turn this way immediately + + self.velocity = '0 0 0'; + self.avelocity = '0 0 0'; + self.adjust_velocity = '-999 -999 -999'; + + if (deathmatch || coop) + { + makevectors(self.angles); + GenerateTeleportEffect(self.origin,0); + } + + spawn_tdeath (self.origin, self,FALSE); + + SetModelAndThinks(); + PlayerSpeed_Calc(self); + W_SetCurrentAmmo (); + + force_retouch = 2; // make sure even still objects get hit + + self.think=player_frames; + thinktime self : 0; + + self.bluemana=self.greenmana=0; +} + +void SetNewParms(void) +{ +} + +void SetChangeParms(void) +{ +} + +/* +============================================================================= + + QUAKED FUNCTIONS + +============================================================================= +*/ + + +/*QUAKED info_player_defender (1 0 0) (-16 -16 -24) (16 16 24) +Defender's starting points +team = 1; +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() info_player_defender = +{ + self.siege_team = ST_DEFENDER; +}; + +/*QUAKED info_player_attacker (1 0 0) (-16 -16 -24) (16 16 24) +Attacker's starting points +team = 2; +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() info_player_attacker = +{ + self.siege_team = ST_ATTACKER; +}; + +/*QUAKED info_player_start (1 0 0) (-16 -16 0) (16 16 56) +The normal starting point for a level. +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() info_player_start = +{ +}; + + +/*QUAKED info_player_start2 (1 0 0) (-16 -16 0) (16 16 56) +Only used on start map for the return point from an episode. +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() info_player_start2 = +{ +}; + + +/* +saved out by quak ed in region mode +*/ +void() testplayerstart = +{ +}; + +/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 0) (16 16 56) +potential spawning position for deathmatch games +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() info_player_deathmatch = +{ + if(!deathmatch) + remove(self); +}; + +/*QUAKED info_player_coop (1 0 1) (-16 -16 0) (16 16 56) DEFAULT +potential spawning position for coop games +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() info_player_coop = +{ +}; + +/* +=============================================================================== + +RULES + +=============================================================================== +*/ + +/* +go to the next level for deathmatch +only called if a time or frag limit has expired +*/ +void() NextLevel = +{ + entity o; + + FindDMLevel(); + + o = spawn(); + o.map = nextmap; + + if (nextmap == "") + { + // find a trigger changelevel + o = find(world, classname, "trigger_changelevel"); + + // go back to start if no trigger_changelevel + if (!o) + { + mapname = "demo1"; + o.map = mapname; + } + } + + gameover = TRUE; + + if(dmMode==DM_SIEGE) + { + o.think = execute_changelevel; + thinktime o : 7; + } + else + { + if (o.nextthink < time) + { + o.think = execute_changelevel; + thinktime o : 0.1; + } + } +}; + +/* +============ +CheckRules + +Exit deathmatch games upon conditions +============ +*/ +void SendPic () +{ + WriteByte (MSG_ALL, SVC_INTERMISSION); + WriteByte (MSG_ALL, self.level); + remove(self); +} + +void VictoryPic(float winpic) +{ +entity pic_maker; + pic_maker=spawn(); + pic_maker.level=winpic; + pic_maker.think = SendPic; + thinktime pic_maker : 5;//wait 15 seconds to show win screen +} + +void KillTeam(float losers) +{ +entity find_def; + find_def=find(world,classname,"player"); + while(find_def) + { + if(find_def.siege_team==losers) + T_Damage(find_def,world,world,5000); + find_def=find(find_def,classname,"player"); + } +} + +void end_siege_game (float loserteam,float winpic) +{ +string printnum; + gameover=TRUE; + if(loserteam==ST_ATTACKER) + sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,"misc/victory.wav",1,ATTN_NONE); + else + sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,"misc/winner.wav",1,ATTN_NONE); + if(!g_init_timelimit) + g_init_timelimit = 30; + printnum=ftos(g_init_timelimit); + cvar_set("timelimit",printnum); + KillTeam(loserteam); + VictoryPic(winpic); + NextLevel (); +} + +void centerprint_all_clients (string victory_msg, entity ignore) +{ +entity found; + found=find(world,classname,"player"); + while(found) + { + if(found.flags&FL_CLIENT&&found!=ignore) + centerprint(found,victory_msg); + found=find(found,classname,"player"); + } + dprint(victory_msg);//for server +} + +void() CheckRules = +{ +float timelimit; +float fraglimit; +//string printnum; + + if (gameover) // someone else quit the game already + return; + + fraglimit = cvar("fraglimit"); + timelimit = cvar("timelimit"); + if(g_fraglimit!=fraglimit||g_timelimit!=timelimit) + { + g_fraglimit=fraglimit; + g_timelimit=timelimit; + updateSiegeInfo(); + } + + timelimit*=60; + if (timelimit>0 && time >= timelimit) + { + if(dmMode==DM_SIEGE)//Siege + { + centerprint_all_clients("The Defenders of The Crown are Victorious!\n",world); + end_siege_game (ST_ATTACKER,WP_DEFENDERS); + return; + } + NextLevel (); + return; + } + + if(fraglimit>0) + if(dmMode==DM_SIEGE)//siege + { + if(defLosses>=fraglimit) + { + centerprint_all_clients("The Defenders of The Crown have been wiped out!!!\n",world); + end_siege_game (ST_DEFENDER,WP_ATTKILL); + return; + } + else if(attLosses>=fraglimit*2) + { + centerprint_all_clients("The Invaders have been wiped out!!!\n",world); + end_siege_game (ST_ATTACKER,WP_DEFENDERS); + return; + } + } + else if (self.frags >= fraglimit) + { + NextLevel (); + return; + } +}; + +//============================================================================ + +void() PlayerDeathThink = +{ +float forward; + + if ((self.flags & FL_ONGROUND)) + { + forward = vlen (self.velocity); + forward = forward - 20; + if (forward <= 0) + self.velocity = '0 0 0'; + else + self.velocity = forward * normalize(self.velocity); + } + +// wait for all buttons released + if (self.deadflag == DEAD_DEAD) + { + if (self.button2 || self.button0) + return; + self.deadflag = DEAD_RESPAWNABLE; + return; + } + +// wait for any button down + if (!self.button2 && !self.button1 && !self.button0) + return; + + self.button0 = 0; + self.button1 = 0; + self.button2 = 0; + respawn(); +}; + +void CheckCliffHold () +{ +vector start, end; + +// check for a hold on to cliff and pull up + makevectors (self.angles); + start = self.origin; + v_forward_z = 0; + normalize(v_forward); + end = start + v_forward*24; + tracearea (start, end, self.mins,self.maxs,TRUE, self); + if (trace_fraction ==1) + return; + // solid in front + start_z=self.absmax_z; + end = start + '0 0 8'*self.scale;//armslength + tracearea (start, end, self.mins,self.maxs,FALSE, self); + if (trace_fraction <1) + return; + //room on top + start = end; + end = start + v_forward*24; + tracearea (start, end, self.mins,self.maxs,TRUE, self); + if (trace_fraction < 1) + return; + // open at arm's length + float liftspeed; + liftspeed=self.strength/self.mass; + self.velocity_z += 7*liftspeed; + if(self.velocity_z<37*liftspeed) + self.velocity_z=37*liftspeed; + else if(self.velocity_z>=177*liftspeed) + self.velocity_z=177*liftspeed; +} + +void CheckWaterJump() +{//fix so can't jump so high that walk on water? +vector start, end; +//this is now handled within physics + return; + +// check for a climb out of water + makevectors (self.angles); + start = self.origin + self.proj_ofs - '0 0 8'; + v_forward_z = 0; + normalize(v_forward); + end = start + v_forward*24; + traceline (start, end, TRUE, self); + if (trace_fraction < 1) + { // solid at waist + if(self.model=="models/sheep.mdl") + start_z = self.origin_z + self.proj_ofs_z + 26;//was absmax - 8 + else + start_z = self.origin_z + self.proj_ofs_z + 6;//was absmax - 8 + end = start + v_forward*24; + self.movedir = trace_plane_normal * -50; + traceline (start, end, TRUE, self); + if (trace_fraction == 1) + { // open at eye level +// self.flags(+)FL_WATERJUMP; //no longer needed thanks to new movement code + self.velocity_z = 225; + self.flags(-)FL_JUMPRELEASED; + self.teleport_time = time + 2; // safety net + return; + } + } +} + +void() PlayerJump = +{ +float wall_jump; + if(self.flags&FL_ONGROUND&&self.beast_time22)) + { + trace_ent.think=catapult_fire; + thinktime trace_ent : 0; + } + } + +// if (self.flags & FL_WATERJUMP) +// return; + + if (self.movetype==MOVETYPE_FLY) + return; + + if (self.waterlevel >= 2) + { + if (self.watertype == CONTENT_WATER) + self.velocity_z = 100*self.scale; + else if (self.watertype == CONTENT_SLIME) + self.velocity_z = 80*self.scale; + else + self.velocity_z = 50*self.scale; + + if(self.playerclass==CLASS_DWARF) + self.velocity_z*=0.3; + + // play swiming sound + if (self.swim_flag < time) + { + self.swim_flag = time + 1; + if (random() < 0.5) + sound (self, CHAN_BODY, "player/swim1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_BODY, "player/swim2.wav", 1, ATTN_NORM); + } + + return; + } + + if (!(self.flags & FL_ONGROUND)) + { + if(self.playerclass==CLASS_ASSASSIN) + { + CheckCliffHold(); + return; + } + + if(cvar("sv_gravity")>400)//On low-grav levels, allow players to push off walls + return; + makevectors(self.v_angle); + traceline(self.origin+self.proj_ofs,self.origin+self.proj_ofs+v_forward*64,FALSE,self); + if(trace_fraction<1&&trace_ent==world&&trace_plane_normal!='0 0 0') + wall_jump=TRUE; + else + return; + } + + if ( !(self.flags & FL_JUMPRELEASED) ) + return; // don't pogo stick + + self.act_state=ACT_JUMP; + + self.flags(-)FL_JUMPRELEASED; + + self.flags(-)FL_ONGROUND; // don't stairwalk + + self.button2 = 0; +// player jumping sound + + if(self.model=="models/sheep.mdl")//self.modelindex==modelindex_sheep) + sheep_sound(1); + else if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + sound (self, CHAN_BODY,"player/assjmp.wav", 1, ATTN_NORM); + else + sound (self, CHAN_BODY,"player/paljmp.wav", 1, ATTN_NORM); + + if(wall_jump) + self.velocity = v_forward*-270*self.scale; +// else//client side now?! +// self.velocity_z = self.velocity_z + 270*self.scale*player_jump_mod[self.playerclass - 1]; +}; + + + + +/* +=========== +WaterMove + +============ +*/ + +void() WaterMove = +{ + +//dprint (ftos(self.waterlevel)); + if (self.movetype == MOVETYPE_NOCLIP) + return; + if (self.health <= 0) + return; + + if ((self.flags & FL_INWATER) && + (self.watertype == CONTENT_WATER) && + (self.waterlevel == 3) && + (!self.splash_time)) + { + DeathBubbles(10); + self.splash_time=TRUE; + if(self.flags2&FL2_HARDFALL) + { + if (self.gravity==1) + { + float hardfall_dmg; + hardfall_dmg=self.health - (random(2) + 5); + if(hardfall_dmg>0) + T_Damage(self,world,world,hardfall_dmg); + } + self.flags2(-)FL2_HARDFALL; + } + self.show_hostile = time + 1; + PlayerSpeed_Calc(self); + } + + if ((self.waterlevel < 3&&self.hull!=HULL_CROUCH)||self.waterlevel<2) // Not up to the eyes + { + if (self.air_finished < time) + { + if (self.model=="models/sheep.mdl") + sheep_sound(1); + else if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + sound (self, CHAN_VOICE, "player/assgasp1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/palgasp1.wav", 1, ATTN_NORM); + } + else if ((self.air_finished < time + 9&&self.playerclass!=CLASS_DWARF)||self.air_finished=3 || (self.waterlevel>=2 &&self.hull==HULL_CROUCH)) + if ((self.air_finished < time) && (!self.rings & RING_WATER)) + { + if(self.playerclass==CLASS_PALADIN&&self.flags&FL_SPECIAL_ABILITY1) + { + self.air_finished = time + 12; + self.dmg = 2; + } + else if (self.pain_finished < time) + {// Drown + self.dmg = self.dmg + 2; + if (self.dmg > 15) + self.dmg = 10; + T_Damage (self, world, world, self.dmg); + self.pain_finished = time + 1; + } + } + + if (!self.waterlevel) + { // Getting out of the water + if (self.flags & FL_INWATER) + { // play leave water sound + sound (self, CHAN_BODY, "raven/outwater.wav", 1, ATTN_NORM); + self.flags(-)FL_INWATER; + } + self.splash_time=FALSE; + return; + } + + if (self.watertype == CONTENT_LAVA) + { // do damage + if (self.dmgtime < time) + { + self.dmgtime = time + 0.5; + + if(!self.flags2&FL2_FIRERESIST) + T_Damage (self, world, world, 5*self.waterlevel); + else + T_Damage (self, world, world, 2*self.waterlevel); + } + } + else if (self.watertype == CONTENT_SLIME) + { // do damage + if (self.dmgtime < time) + { + self.dmgtime = time + 1; + T_Damage (self, world, world, 4*self.waterlevel); + } + } + + // Just entering fluid + if (!(self.flags & FL_INWATER)) + { + // player enter water sound + if (self.watertype == CONTENT_LAVA) + sound (self, CHAN_BODY, "raven/inlava.wav", 1, ATTN_NORM); + else if (self.watertype == CONTENT_WATER) + { + sound (self, CHAN_BODY, "raven/inh2o.wav", 1, ATTN_NORM); + } +// else if (self.watertype == CONTENT_SLIME) +// sound (self, CHAN_BODY, "player/slimbrn1.wav", 1, ATTN_NORM); + + self.flags(+)FL_INWATER; + self.dmgtime = 0; + + } + +// if (! (self.flags & FL_WATERJUMP) ) + if(self.playerclass==CLASS_DWARF) + self.velocity = self.velocity - 0.95*self.waterlevel*frametime*self.velocity; + else + self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity; +}; + +void CheckCrouch (void) +{ + if(self.playerclass==CLASS_DWARF) + return; + + if ((self.crouch_time) && (self.crouch_time < time)) // Time to crouch or uncrouch a little + { + if (self.hull==HULL_CROUCH) // Player crouching + { + self.crouch_stuck = 0; + self.view_ofs_z -= 10; + self.proj_ofs_z -= 10; + if (self.view_ofs_z < 24) + { + self.view_ofs_z = 24; + self.proj_ofs_z = 18; + self.crouch_time = 0; + } + else + self.crouch_time = time + HX_FRAME_TIME/4; + } + else + { + self.view_ofs_z += 10; + self.proj_ofs_z += 10; + if (self.view_ofs_z > 50) + { + self.view_ofs_z = 50; + self.proj_ofs_z = 44; + self.crouch_time = 0; + } + else + self.crouch_time = time + HX_FRAME_TIME/4; + } + } + + if(self.model!="models/yakman.mdl") + { + if ((self.flags2 & FL2_CROUCHED||self.model=="models/sheep.mdl"||self.flags2&FL2_CROUCH_TOGGLE) && (self.hull!=HULL_CROUCH)) + PlayerCrouching (); + else if (((!self.flags2 & FL2_CROUCHED&&self.model!="models/sheep.mdl"&&!self.flags2&FL2_CROUCH_TOGGLE) && (self.hull==HULL_CROUCH)) || + (self.crouch_stuck)) // If stuck, constantly try to unstick + PlayerUnCrouching(); + } +} + +void CheckIncapacities () +{ +vector dir; + if(self.frozen>0) + if(self.flags2&FL_ALIVE&&self.health) + { + if(self.colormap>144) + { + self.colormap-=0.5; + self.abslight-=0.025; + } + else + { + self.colormap=0; + self.abslight=0.5; + self.skin=GLOBAL_SKIN_ICE; + } + if(self.pausetime<=time) + { + if(self.skin==GLOBAL_SKIN_ICE) + self.skin=self.oldskin; + self.colormap=0; + self.abslight=0; + self.thingtype=THINGTYPE_FLESH; + self.drawflags(-)DRF_TRANSLUCENT|MLS_ABSLIGHT; + self.frozen=FALSE; + self.artifact_active(-)ARTFLAG_FROZEN; + self.touch=PlayerTouch; + self.credit_enemy=world; + } + } + else + self.frozen=self.pausetime=self.teleport_time=0; + + + if(self.pausetime>time&&self.model!=self.headmodel) + { + if(self.model=="models/flesh1.mdl") + { + dir=normalize(self.wallspot-self.origin+self.view_ofs); + dir=vectoangles(dir); + self.o_angle_x=dir_x*-1; + self.o_angle_y=dir_y; + self.o_angle_z=self.v_angle_z; + } + else if(!self.flags2&FL_ALIVE&&self.enemy.flags2&FL_ALIVE)//&&visible(self.enemy)) + {//face enemy + self.o_angle=normalize(self.enemy.origin+self.enemy.proj_ofs-self.origin+self.view_ofs); + self.o_angle=vectoangles(self.o_angle); + self.o_angle_x*=-1;//have to reverse the pitch + if(self.o_angle_y>180) + self.o_angle_y-=360; + else if(self.o_angle_y<-180) + self.o_angle_y+=360; + self.o_angle_z=self.v_angle_z; + self.o_angle-=self.v_angle; + if(self.o_angle_x>7) + self.o_angle_x=7; + else if(self.o_angle_x<-7) + self.o_angle_x=-7; + if(self.o_angle_y>10) + self.o_angle_y=10; + else if(self.o_angle_y<-10) + self.o_angle_y=-10; + self.o_angle+=self.v_angle; + } + + msg_entity = self; + WriteByte (MSG_ONE, 10); + WriteAngle (MSG_ONE, self.o_angle_x); + WriteAngle (MSG_ONE, self.o_angle_y); + WriteAngle (MSG_ONE, self.o_angle_z); + if(self.flags&FL_ONGROUND) + self.velocity='0 0 0'; + self.button0=0; + self.button2=0; + if((self.impulse != 23)&&(self.impulse != 100)) + self.impulse=0; //allow item use while frozen + else if(!(self.flags2 & FL_ALIVE)) //unless also dead + self.impulse = 0; + } + + if(self.flags2&FL_CHAINED) + self.button1=self.button2=0;//self.button0= +} + +/* +Climbing +*/ + +void ClimbDrop () +{ +vector f_dir; + f_dir = v_forward; + if(f_dir_z>0.2) + f_dir_z=0.2; + centerprint(self,"Jumping Mode\n"); + sound (self, CHAN_VOICE,"player/assjmp.wav", 1, ATTN_NORM); + self.climbing = FALSE; + // self.velocity_z = self.velocity_z + 270*self.scale; + self.velocity = self.velocity + f_dir*300; +} + +void Climb () +{ +vector spot; + makevectors (self.v_angle); + if(self.flags&FL_ONGROUND || (self.climbing && (vlen(self.climbspot - (self.origin + self.view_ofs)) > 64))) + { + ClimbDrop(); + return; + } + + spot=self.origin+self.view_ofs; + traceline(spot,spot+v_forward*64,FALSE,self); + if(trace_ent.solid==SOLID_BSP) + if(trace_fraction<1&&!trace_inwater) + { + if(trace_plane_normal_z<0.5) + if(trace_plane_normal_z>-0.1) + { + if(self.climbing==FALSE) + centerprint(self,"Climbing Mode\n"); + sound(self,CHAN_AUTO,"weapons/met2stn.wav",1,ATTN_NORM); + sound (self, CHAN_VOICE,"player/assjmp.wav", 1, ATTN_NORM); +// self.effects(+)EF_MUZZLEFLASH; + CreateSpark(trace_endpos-v_forward*3); + self.climbing=TRUE; + self.climbspot=trace_endpos; + self.last_climb=time; + } + } + else if(self.climbing) + {//climb up + spot = self.origin+v_forward*18; + if (pointcontents(spot)==CONTENT_SOLID) + { + self.climbing=TRUE; + self.climbspot=trace_endpos; + self.last_climb=time; + } + else if(random()<0.2) + ClimbDrop(); + else//give them a few chances to try to grab another surface + { + sound (self, CHAN_VOICE,"player/assjmp.wav", 1, ATTN_NORM); + self.last_climb=time - 1; + } + } + self.button2=0; +} + +void CheckSniperBow () +{ + if(self.playerclass==CLASS_ASSASSIN&&self.weapon==IT_WEAPON3&&self.weaponmodel=="models/xbow2.mdl") + { + string new_fov; + //string printnum; + if(self.attack_finished>time||(!self.button0&&self.fov_val>10&&self.zoom_timetime) + dprint("att_fin\n"); + if(!self.button0&&self.fov_val>10&&self.zoom_time=11&&self.button0&&self.cnt_arrows) + { + //dprint("Zoom: can't fire -zoomin in"); + self.zoom_time=time+0.5; + self.fov_val-=1; + new_fov=ftos(self.fov_val); + stuffcmd(self,"fov "); + stuffcmd(self,new_fov); + stuffcmd(self,"\n"); + self.button0=FALSE; + } + } + + if(self.puzzle_inv1!=g_keyname)//key carrier can't regen mana + { + if(self.siege_team&&gamestarted) + if(self.playerclass!=CLASS_ASSASSIN&&self.playerclass!=CLASS_PALADIN&&self.playerclass!=CLASS_DWARF&&self.beast_time=1) + { + switch(self.playerclass) + { + case CLASS_CRUSADER: + self.bluemana+=t_interval/2; + if(self.bluemana>self.max_mana) + self.bluemana=self.max_mana; + break; + case CLASS_NECROMANCER: + self.greenmana+=t_interval/2; + if(self.greenmana>self.max_mana) + self.greenmana=self.max_mana; + break; + case CLASS_SUCCUBUS: + self.greenmana+=t_interval/4; + if(self.greenmana>self.max_mana) + self.greenmana=self.max_mana; + break; + } + + self.last_time=time; + } + } + } +} +/* +================ +PlayerPreThink + +Called every frame before physics are run +================ +*/ +void() PlayerPreThink = +{ + vector spot1, spot2; + +// self.oldorigin=self.origin; +// if(random()<0.01) +// { +// dprintf("player lighting: %s\n",self.light_level); + /* + if(self.flags & FL_INWATER) + dprint("I'm in water!\n"); + if(self.siege_team) + dprintf("I'm on team %s\n",self.siege_team);*/ +// } + +// if(self.velocity!='0 0 0'&&random()<0.01) +// dprintv("pre_th: %s\n",self.velocity); + + /*If have problems being thrown out of world when die + if ((self.health<=0) && (self.movetype!=MOVETYPE_NOCLIP)) + { + if(pointcontents(self.origin)==CONTENT_SOLID&&self.origin!='0 0 0') + { + self.velocity='0 0 0'; + self.solid=SOLID_NOT; + self.movetype=MOVETYPE_NOCLIP; + setorigin(self,self.oldorigin); + } + } +*/ + if (!self.flags & FL_INWATER) self.aflag = 0; + +// dprint(teststr[1]); +// dprint("\n"); + + if (intermission_running) + { + IntermissionThink (); // otherwise a button could be missed between + return; // the think tics + } + + if (self.view_ofs == '0 0 0'&& + self.viewentity.classname!="chasecam"&& + !self.button0&&!self.button2)//Causing them to not be able to respawn? + return; // intermission or finale + + if (self.adjust_velocity_x != -999) + { + self.velocity_x = self.adjust_velocity_x; + } + if (self.adjust_velocity_y != -999) + { + self.velocity_y = self.adjust_velocity_y; + } + if (self.adjust_velocity_z != -999) + { + self.velocity_z = self.adjust_velocity_z; + } + self.adjust_velocity = '-999 -999 -999'; + + if (self.deadflag < DEAD_DYING) + CheckSniperBow(); + CheckIncapacities(); + + if(self.viewentity!=self) + { + CameraViewPort(self,self.viewentity); + if(self.viewentity.classname!="chasecam")//&&self.viewentity.classname!="camera_remote") + { + self.weaponframe=self.viewentity.weaponframe; + self.weaponmodel=self.viewentity.weaponmodel; + CameraViewAngles(self,self.viewentity); + } + else + self.weaponmodel=""; + } + + makevectors (self.v_angle); // is this still used + + self.friction=0; // If in entity FRICTION_TOUCH will reset this + + CheckRules (); + CheckRings (); + CheckAbilities (); + CheckCrouch (); + + WaterMove (); + + if (self.waterlevel == 2) + CheckWaterJump (); + + if (self.deadflag >= DEAD_DEAD) + { + PlayerDeathThink (); + return; + } + // Turn off plaque if it is on + if (self.plaqueflg) + { // Is moving or looking around so kill plaque + if (((self.velocity_x) || (self.velocity_y) || (self.velocity_z)) || + (self.plaqueangle != self.v_angle)) + { + makevectors (self.v_angle); + + spot1 = self.origin + self.view_ofs; + spot2 = spot1 + (v_forward*25); // Look just a little ahead + traceline (spot1, spot2 , FALSE, self); + + if ((trace_fraction == 1.0) || (trace_ent.classname!="plaque")) + { + traceline (spot1, spot2 - (v_up * 30), FALSE, self); // 30 down + + if ((trace_fraction == 1.0) || (trace_ent.classname!="plaque")) + { + traceline (spot1, spot2 + v_up * 30, FALSE, self); // 30 up + + if ((trace_fraction == 1.0) || (trace_ent.classname!="plaque")) + { + self.plaqueflg=0; + msg_entity = self; + plaque_draw(MSG_ONE,0); + } + } + } + + if (self.plaqueflg) + self.plaqueangle = self.v_angle; + } + } + + // Twitch every so often if not moving + if ((!self.velocity_x) && (!self.velocity_y) && (!self.velocity_z)) + { + // FIXME: needs to be a random number between 5 - 8 minutes or so + if ((self.camptime + 600) < time) + { + if (self.playerclass==CLASS_PALADIN&&self.weapon==IT_WEAPON1) + { + vorpal_twitch(); + self.camptime = time + random(840,420); + } + } + } + else + self.camptime = time + random(420,840); + + + if (self.deadflag == DEAD_DYING) + return; // dying, so do nothing + + if (self.button2) + { + if(self.climbing&&self.last_climb+3 self.attack_finished && self.weapon != IT_WEAPON1) + { + if (((self.weapon == IT_WEAPON3) && (self.greenmana<1)) || + ((self.weapon == IT_WEAPON4) && (self.bluemana<1) && (self.greenmana<1))) + { + W_BestWeapon (); + W_SetCurrentWeapon (); + } + }*/ +}; + +void CheckRings (void) +{ + entity victim; + vector dir; + float chance; + + if (self.health <= 0) + return; + + if((self.flags2&FL2_EXCALIBUR&&self.health3||self.greenmana>3) + { + dprint("Error! Player started with mana!!!\n"); + self.bluemana=self.greenmana=0; + } + if (self.invincible_time < time) + remove_invincibility(self); + else if ((self.invincible_time - 10) < time) + self.artifact_low = self.artifact_low | ART_INVINCIBILITY; + /* + if(self.playerclass==CLASS_SUCCUBUS) + { + vector vect, v1, v2; + + vect='0 0 0'; + vect_y=(self.invincible_time - time)*480; + makevectors(vect); + vect = self.origin + self.proj_ofs + v_forward*32; + if (random() < 0.5) + v1 = randomv('-10 -10 25', '10 10 45'); + v2 = randomv('-10 -10 25', '10 10 45'); + particle2(vect, v1, v2, 416,PARTICLETYPE_FIREBALL,7); + vect = self.origin + self.proj_ofs - v_forward*32; + v1_z=v2_z=0; + particle2(vect,v1, v2, 135,PARTICLETYPE_REDFIRE,3); + + } + */ + } + +// if (self.artifact_active & ART_TOMEOFPOWER) +// { + if ((self.drawflags & MLS_MASKIN) != MLS_POWERMODE) + self.drawflags = (self.drawflags & MLS_MASKOUT)| MLS_POWERMODE; + + if (self.tome_time < time) + { + self.artifact_low = self.artifact_low - (self.artifact_low & ART_TOMEOFPOWER); + self.artifact_active = self.artifact_active - (self.artifact_active & ART_TOMEOFPOWER); + self.tome_time = 0; + self.drawflags = (self.drawflags & MLS_MASKOUT)| 0; + } + else if ((self.tome_time - 10) < time) + self.artifact_low = self.artifact_low | ART_TOMEOFPOWER; +// } + + +// invisibility + if (self.artifact_active & ART_INVISIBILITY) + { + if (self.invisible_time < time) + { // just stopped + self.artifact_low = self.artifact_low - (self.artifact_low & ART_INVISIBILITY); + self.artifact_active = self.artifact_active - (self.artifact_active & ART_INVISIBILITY); + self.invisible_time = 0; + msg_entity=self; + WriteByte(MSG_ONE, SVC_CLEAR_VIEW_FLAGS); + WriteByte(MSG_ONE,DRF_TRANSLUCENT); + self.effects(-)EF_NODRAW|EF_LIGHT; + self.skin=self.oldskin; + self.drawflags(-)DRF_TRANSLUCENT; + } + else + { + if ((self.invisible_time - 10) < time) + self.artifact_low = self.artifact_low | ART_INVISIBILITY; + } + + } + + if (self.sheep_timetime||self.button0||self.button2) + CameraReturn (); + } + else if (self.camera_time < time) + CameraReturn (); + } +}; + +/* +================ +Player Touch + +Mainly used to allow player to climb on top of monsters, +other players, etc. +================ +*/ +void PlayerTouch (void) +{ + + if(self.effects & EF_ONFIRE) + if(random()self.fire_damage) + self.fire_damage+=1; + } + else if(random()=100&&self.last_onground+0.3=THINGTYPE_WEBS)&&self.last_impact+0.1<=time) + obj_fly_hurt(other); + + if(other==world) + return; + + if(coop||deathmatch) +/* { + if(other.classname=="player") + { + entity pusher,pushee; + if(self.adjust_velocity!='0 0 0') + self.velocity=self.adjust_velocity; + if(other.adjust_velocity!='0 0 0') + other.velocity=other.adjust_velocity; + if(self.velocity!='0 0 0') + { + pusher=self; + pushee=other; + } + else if(other.velocity!='0 0 0') + { + pusher=other; + pushee=self; + } + if(pusher!=world) + { + sprint(pusher,PRINT_HIGH,"You are pushing\n"); + sprint(pushee,PRINT_HIGH,"You are being pushed\n"); + if(normalize(pusher.velocity)*normalize(pushee.origin-pusher.origin)>0.2) + { + if(fabs(pushee.origin_z-pusher.origin_z)<48) + { + float push_mod; + if(!pushee.artifact_active&ARTFLAG_FROZEN) + pushee.credit_enemy=pusher; + if(pusher.flags&FL_ONGROUND) + push_mod=.33; + else + push_mod=.77; + if(pushee.flags&FL_ONGROUND&&pusher.velocity_z<0) + { + pushee.velocity_x=(pushee.velocity_x/push_mod+pusher.velocity_x*push_mod)*push_mod; + pushee.velocity_y=(pushee.velocity_y/push_mod+pusher.velocity_y*push_mod)*push_mod; + } + else + pushee.velocity=(pushee.velocity*(1/push_mod)+pusher.velocity*push_mod)*push_mod; + pushee.flags(-)FL_ONGROUND; + pushee.adjust_velocity=pushee.velocity; + } + } + } + else + sprint(self,PRINT_HIGH,"Neither one is moving\n"); + } + } +*/ + if(random()<0.5) + if(other.classname=="player") + if(self.velocity!='0 0 0')//push other players + if(normalize(self.velocity)*normalize(other.origin-self.origin)>0.2) + if(fabs(other.origin_z-self.origin_z)<48) + { + float push_mod; + if(self.flags&FL_ONGROUND) + push_mod=0.33; + else + push_mod=0.77; + if(other.flags&FL_ONGROUND&&self.velocity_z<0) + { + other.velocity_x=(other.velocity_x/push_mod+self.velocity_x*push_mod)*push_mod; + other.velocity_y=(other.velocity_y/push_mod+self.velocity_y*push_mod)*push_mod; + other.flags(-)FL_ONGROUND; + } + else + other.velocity=(other.velocity*(1/push_mod)+self.velocity*push_mod)*push_mod; + } + + if(self.flags&FL_ONGROUND) + return; + + if((other.classname=="player"||other.flags&FL_ONGROUND||other.health)&&self.origin_z>=(other.absmin_z+other.absmax_z)*0.5&&self.velocity_z<10) + self.flags(+)FL_ONGROUND; +} + +/* +================ +PlayerPostThink + +Called every frame after physics are run +================ +*/ +void() PlayerPostThink = +{ + if (intermission_running) + return; + + if (self.deadflag) + return; +// do weapon stuff + + W_WeaponFrame (); + + if(self.viewentity.classname=="chasecam") + self.weaponmodel=""; + +// check to see if player landed and play landing sound + if ((self.jump_flag*(self.mass/10) < -300) && self.flags & FL_ONGROUND && self.health > 0) + { + if(self.beast_time=time||self.playerclass==CLASS_DWARF) + self.jump_flag/=2; + if (self.watertype == CONTENT_WATER) + sound (self, CHAN_BODY, "player/h2ojmp.wav", 1, ATTN_NORM); + else + if (self.jump_flag*(self.mass/10) < -500)//was -650 + { + if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + sound (self, CHAN_VOICE, "player/asslnd.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/pallnd.wav", 1, ATTN_NORM); + if(self.health > 5) + { + self.deathtype = "falling"; + T_Damage (self, world, world, 5); + } + } + else + sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM); + } + if(self.scale>1&&self.jump_flag*(self.mass/10) < -500) + MonsterQuake((self.mass/500)*self.jump_flag); + + self.jump_flag=0; + + if(self.flags2&FL2_HARDFALL) + { + if(self.gravity==1 && self.beast_time0) + T_Damage(self,world,world,hardfall_dmg); + } + self.flags2(-)FL2_HARDFALL; + } + } + + if (!(self.flags & FL_ONGROUND)) + { + if(self.playerclass==CLASS_SUCCUBUS) + if(self.flags&FL_SPECIAL_ABILITY1) + if(self.button2&&self.velocity_z<=0&&!self.waterlevel) + { + if(self.gravity==self.standard_grav&&self.standard_grav>0.2) + sound (self, CHAN_BODY, "succubus/fwoomp.wav", 1, ATTN_NORM); + self.gravity=0.2; + self.flags(-)FL_JUMPRELEASED; + } + else + self.gravity=self.standard_grav; + + self.jump_flag=self.velocity_z; + } + else + { + self.last_onground = time; + } + + CheckPowerups (); + + if(self.artifact_flags & AFL_TORCH) + { + if (self.torchtime < time) + self.torchthink (); + if (self.frozen) + { + self.frozen -= 8; + if(self.frozen <= 0) + { + self.attack_finished = time; + self.pausetime = time; //so it'll release you + thinktime self : 0.01; + self.frozen = 0.01; //as soon as it checks for frozen + } + } + } + +// if ((self.artifact_flags & AFL_TORCH) && (self.torchtime < time)) +// self.torchthink (); + + if ((self.artifact_flags & AFL_SUPERHEALTH) && (self.healthtime < time)) + DecrementSuperHealth (); + + if(self.climbing==TRUE) + { + self.velocity='0 0 0'; + self.velocity = normalize(self.climbspot - (self.origin+self.view_ofs))*80; + } +}; + + +/* +=========== +ClientConnect + +called when a player connects to a server +============ +*/ +void() ClientConnect = +{ + bprint (PRINT_HIGH, self.netname); + bprinti (PRINT_HIGH, STR_JOINEDTHEGAME); + + if(dmMode == DM_CAPTURE_THE_TOKEN) + { + centerprint(self, "Server is running Hoard the Icon..."); + } + else if(dmMode == DM_HUNTER) + { + centerprint(self, "Server is running Hunter..."); + } + else if(dmMode == DM_HUNTER) + { + sprint(self,PRINT_HIGH,"Welcome to Siege v0.02! by:@Michael Gummelt, Perfecto Cuervo, Josh Weier, Jeremy Statz & Nathan Albury@Courtesy Raven Software\n"); + centerprint(self, "Server is running Siege!\n"); + } + +// a client connecting during an intermission can cause problems + if (intermission_running) + ExitIntermission (); +}; + + +/* +=========== +ClientDisconnect + +called when a player disconnects from a server +============ +*/ +void() ClientDisconnect = +{ +// entity lastleader,newking; + entity curPlayer; + + if (gameover) + return; + // if the level end trigger has been activated, just return + // since they aren't *really* leaving + + // let everyone else know + bprintname (PRINT_HIGH, self); + bprinti (PRINT_HIGH, STR_LEFTTHEGAMEWITH); + bprint (PRINT_HIGH, ftos(self.frags)); + bprinti (PRINT_HIGH, STR_FRAGS); + sound (self, CHAN_BODY+PHS_OVERRIDE_R, "player/leave.wav", 1, ATTN_NONE); + if(self.puzzle_inv1!="") + { + self.puzzle_id=self.puzzle_inv1; + DropPuzzlePiece(); + self.puzzle_inv1=self.puzzle_id=""; + } + GibPlayer('0 0 1'); + set_suicide_frame (); + + if(dmMode == DM_HUNTER) + { // to properly remove the guy... + self.gameFlags (+) GF_HAS_LEFT_HUNTER; + + curPlayer = find(world, classname, "player"); + while(curPlayer != world) + { + if(curPlayer.targetPlayer == self) + { + curPlayer.targetPlayer = world; + } + curPlayer = find(curPlayer, classname, "player"); + } + } +}; + +/* +=========== +ClientObituary + +called when a player dies +============ +*/ +void(entity targ, entity attacker, entity inflictor) ClientObituary = +{ + float rnum,tclass,aclass,reversed,powered_up, exp_mult; + string iclass; + float deathstring, deathstring2; + if (targ.classname != "player") + return; + + if(self.deathtype=="smitten") + { + centerprint(self,"GOD Has Stricken You Down!\n"); + return; + } + + tclass=targ.playerclass; + aclass=attacker.playerclass; + iclass=inflictor.classname; + powered_up=inflictor.frags; + exp_mult=1; + rnum = random(); + + if (targ.deathtype == "teledeath") + { + selectprintname (PRINT_MEDIUM, targ); + selectprinti (PRINT_MEDIUM, STR_WASTELEFRAGGEDBY); + selectprint (PRINT_MEDIUM, attacker.netname);//this guy might be freshly spawned. + selectprint (PRINT_MEDIUM, "\n"); + return; + } + + if (targ.deathtype == "teledeath2") + { + selectprint (PRINT_MEDIUM, "The power of invincibility reflects "); + selectprint (PRINT_MEDIUM, targ.netname); + selectprint (PRINT_MEDIUM, "'s telefrag\n"); + return; + } + + if (targ.deathtype == "teledeath3") + { + selectprint (PRINT_MEDIUM, attacker.netname); + selectprint (PRINT_MEDIUM, " telefragged "); + selectprintname (PRINT_MEDIUM, targ); + selectprint (PRINT_MEDIUM, ", thier own teammate!\n"); + return; + } + + if (targ.deathtype == "teledeath4") + { + if (targ != attacker)//i get sent here by each client--only print out message once + { + selectprint (PRINT_MEDIUM, attacker.netname); + selectprint (PRINT_MEDIUM, "'s invincibility met "); + selectprint (PRINT_MEDIUM, targ.netname); + selectprint (PRINT_MEDIUM, "'s invincibility and mutual annihilation resulted!\n"); + } + return; + } + + if(dmMode==DM_SIEGE) + { + if(targ.siege_team==ST_DEFENDER)//Siege- defender died + defLosses+=1; + else if(targ.siege_team==ST_ATTACKER)//Siege- attacker died + attLosses+=1; + } + + if (attacker.classname == "player") + { + if (targ == attacker) + { + // killed self + attacker.frags -= 1; + selectprintname (PRINT_MEDIUM, targ); + + if(random()<0.5) + selectprinti (PRINT_MEDIUM, STR_MUSTBEMASOCHIST); + else + selectprinti (PRINT_MEDIUM, STR_BECOMESBORED); + return; + } + else if ((dmMode==DM_SIEGE&&targ.siege_team==attacker.siege_team) || ( (teamplay == 2) && (targ.team > 0)&&(targ.team == attacker.team) )) + { + if (rnum < 0.25) + deathstring = STR_MOWSTEAMMATE; + else if (rnum < 0.50) + deathstring = STR_CHECKSGLASSES; + else if (rnum < 0.75) + deathstring = STR_GETSFRAGFOROTHER; + else + deathstring = STR_LOSESANOTHERFRIEND; + selectprintname (PRINT_MEDIUM, attacker); + selectprinti (PRINT_MEDIUM, deathstring); + attacker.frags -= 1; + return; + } + else + { + attacker.frags += 1; + + rnum = attacker.weapon; + if(attacker.model=="models/sheep.mdl") + { + deathstring = STR_WASNIBBLED; + deathstring2 = STR_THESHEEP; + } + else if(targ.decap==1) + { + if(tclass==CLASS_ASSASSIN||tclass==CLASS_SUCCUBUS) + deathstring = STR_LOSTHERHEAD; + else + deathstring = STR_LOSTHISHEAD; + deathstring2 = STR_EXCLAMRETURN; + } + else if (targ.decap==2) + { + if (tclass==CLASS_ASSASSIN||tclass==CLASS_SUCCUBUS) + { + deathstring = STR_GOTHERHEADBLOWN; + deathstring2 = STR_EXCLAMRETURN; + } + else + { + deathstring = STR_GOTHISHEADBLOWN; + deathstring2 = STR_EXCLAMRETURN; + } + } + else if (iclass=="cube_of_force") + { + deathstring = STR_WASVENTILATED; + deathstring2 = STR_SFORCECUBE; + } + else if(iclass=="tripwire") + { + deathstring = STR_TRIPPEDON; + deathstring2 = STR_STRIPPEDWIRE; + } + else if(iclass=="fireballblast") + { + deathstring = STR_WASBLOWNAWAY; + deathstring2 = STR_SDELAYEDFIREBALL; + } + else if(iclass=="proximity") + { + deathstring = STR_GOTTOOCLOSE; + deathstring2 = STR_SPROXIMITYGLYPH; + } + else if(iclass=="timebomb") + { + deathstring = STR_WASINWRONGPLACE; + deathstring2 = STR_STIMEBOMB; + } + else if(iclass=="poison grenade") + { + deathstring = STR_CHOKEDON;//" choked on "; + deathstring2 = STR_SGAS;//"'s gas!\n"; + } + else if(iclass=="tornato") + { + deathstring = STR_ISNTINKANSAS; + deathstring2 = STR_STORNADO; + } + else if(iclass=="blizzard") + { + deathstring = STR_WASSNOWEDIN; + deathstring2 = STR_SBLIZZARD; + } + else if(targ.deathtype=="hammercrush") + { + deathstring = STR_WASCRUSHEDBYRIGHTEOUS; + deathstring2 = STR_SHAMMER; + } + else if (iclass == "monster_imp_lord") + { + deathstring =STR_WASJACKEDUP; + deathstring2 =STR_SSUMMONEDIMP; + } + else if (iclass == "barrel") + { + if(self.frags) + {//blown up by ballista + deathstring =STR_BLOWNUP; + deathstring2 =STR_BALLISTA; + } + else + { + deathstring =STR_BLOWNUP; + deathstring2 =STR_CRACKSHOT; + } + } + else if (iclass == "balbolt") + { + deathstring =STR_SKEWERED; + deathstring2 =STR_BALLISTA; + } + else if(inflictor.frags==2&&iclass!="player") + { + deathstring = STR_WASDESTROYEDBYPOWER; + deathstring2 = STR_SDISCOFREPUL; + } + else if (rnum == IT_WEAPON1) + { + if(attacker.artifact_active&ART_TOMEOFPOWER) + exp_mult=1.5; + else + exp_mult=2; + if(aclass==CLASS_ASSASSIN) + { + deathstring = STR_GOTPENETRATED; + deathstring2 = STR_SKATAR; + } + else if(aclass==CLASS_CRUSADER) + { + if(exp_mult==1.5) + { + deathstring = STR_WASFRIEDBYHOLY; + deathstring2 = STR_SMJOLNIR; + } + else + { + deathstring = STR_WASWHALLOPED; + deathstring2 = STR_SHAMMER2; + } + } + else if(aclass==CLASS_PALADIN) + { + deathstring = STR_WASCUTTOPIECES; + deathstring2 = STR_SVORPALSWORD; + } + else if(aclass==CLASS_DWARF) + { + deathstring = STR_WASWHALLOPED; + deathstring2 = STR_SHAMMER2; + } + else if(aclass==CLASS_SUCCUBUS) + { + deathstring = STR_GOTBURNEDBY;//" got burned by "; + deathstring2 = STR_SBLOODFIRE;//"'s BloodFire\n"; + } + else + { + deathstring = STR_WASSLICEDANDDICED; + deathstring2 = STR_SSICKLE; + } + } + else if (rnum == IT_WEAPON2) + { + if(powered_up) + exp_mult=1; + else + exp_mult=1.2; + if(aclass==CLASS_ASSASSIN) + { + deathstring = STR_WASSTUCKLIKEPIG; + deathstring2 = STR_SARROWS; + } + else if(aclass==CLASS_CRUSADER) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_PALADIN) + { + deathstring = STR_GOTNASTYPAPER; + deathstring2 = STR_SAXEBLADE; + } + else if(aclass==CLASS_DWARF) + { + deathstring = STR_GOTNASTYPAPER; + deathstring2 = STR_SAXEBLADE; + } + else if(aclass==CLASS_SUCCUBUS) + { + deathstring = STR_WASCUTTOPIECES; + deathstring2 = STR_SVORPALSWORD; + } + else + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + } + else if (rnum == IT_WEAPON3) + { + if(powered_up) + exp_mult=0.8; + else + exp_mult=1; + if(aclass==CLASS_ASSASSIN) + { + deathstring = STR_TOOKONEOF; + deathstring2 = STR_SARROWTOHEART; + } + else if(aclass==CLASS_CRUSADER) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_PALADIN) + { + deathstring = STR_WASSTUCKLIKEPIG; + deathstring2 = STR_SARROWS; + } + else if(aclass==CLASS_DWARF) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_SUCCUBUS) + { + deathstring = STR_WASSTUCKLIKEPIG; + deathstring2 = STR_SARROWS; + } + else + { + deathstring = STR_WASMOWEDDOWN; + deathstring2 = STR_SMAGICMISSILES;//NO REPEATY PLEEZ!!!!! + } + } + else if (rnum == IT_WEAPON4) + { + if(powered_up) + exp_mult=0.5; + else + exp_mult=0.8; + if(aclass==CLASS_ASSASSIN) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_CRUSADER) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_PALADIN) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_DWARF) + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + else if(aclass==CLASS_SUCCUBUS) + { + reversed=TRUE; + deathstring = STR_OPENEDWHOOPASS; + deathstring2 = STR_EXCLAMRETURN;//HEY STEVE!! DON'T RE-ENTER ME IN STRING LIST!!!! + } + else + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + } + else + { + deathstring = STR_NULL; + deathstring2 = STR_NULL; + } + if(reversed) + { + selectprintname (PRINT_MEDIUM, attacker); + selectprinti (PRINT_MEDIUM, deathstring); + selectprintname (PRINT_MEDIUM, targ); + selectprinti (PRINT_MEDIUM, deathstring2); + } + else + { + selectprintname (PRINT_MEDIUM, targ); + selectprinti (PRINT_MEDIUM, deathstring); + selectprintname (PRINT_MEDIUM, attacker); + selectprinti (PRINT_MEDIUM, deathstring2); + } + } + return; + } + + // was not killed by a player + else + { + targ.frags -= 1; + selectprintname (PRINT_MEDIUM, targ); + + if (attacker.flags & FL_MONSTER) + { + if (attacker.classname == "monster_pirhana") + if(attacker.netname=="Chucky") + selectprint (PRINT_MEDIUM, " was nibbled in the nads to death by Chunky the pirhana!\n"); + else + selectprint (PRINT_MEDIUM, " was skeletonized in mere seconds by the ravenous pirhana!\n"); + if(attacker.model=="models/sheep.mdl") + if(random()<0.5) + selectprint (PRINT_MEDIUM, " was savagely mauled by a sheep!\n"); + else + selectprint (PRINT_MEDIUM, " says 'HELLO DOLLY!'\n"); + if (attacker.classname == "monster_archer") + selectprint (PRINT_MEDIUM, " was skewered by an Archer!\n"); + if (attacker.classname == "monster_archer_lord") + selectprint (PRINT_MEDIUM, " got Horshacked!\n"); + if (attacker.classname == "monster_fallen_angel") + selectprint (PRINT_MEDIUM, " was felled by the Fallen Angel\n"); + if (attacker.classname == "monster_fallen_angel_lord") + selectprint (PRINT_MEDIUM, " was decimated by a Fallen Angel Lord!\n"); + if (attacker.classname == "monster_golem_bronze") + if(targ.decap==1) + selectprint (PRINT_MEDIUM, "'s head was taken as a trophy for the Bronze Golem!\n"); + else if(targ.decap==2) + selectprint (PRINT_MEDIUM, " became a permanent stain on the wall!\n"); + else + selectprint (PRINT_MEDIUM, " was squished like an insect by a Bronze Golem!\n"); + if (attacker.classname == "monster_golem_iron") + { + if (inflictor.classname == "golem_iron_proj") + selectprint(PRINT_MEDIUM, " felt the sting of the Iron Golem's jewel!\n"); + else if(targ.decap==2) + selectprint (PRINT_MEDIUM, "'s brains make nice wall decorations!\n"); + else + selectprint (PRINT_MEDIUM, " was crushed by the Iron Golem's fist!\n"); + } + if (attacker.classname == "monster_golem_stone") + if(targ.decap==2) + selectprint (PRINT_MEDIUM, " is feeling a little light-headed!\n"); + else + selectprint (PRINT_MEDIUM, " was pummeled by a Stone Golem!\n"); + if (attacker.classname == "monster_golem_crystal") + selectprint (PRINT_MEDIUM, " was mangled by the Enchanted Crystal Golem!\n"); + if (attacker.classname == "monster_hydra") + selectprint (PRINT_MEDIUM, " becomes food for the Hydra!\n"); + if (attacker.classname == "monster_imp_fire") + selectprint (PRINT_MEDIUM, " was roasted by a Fire Imp!\n"); + if (attacker.classname == "monster_imp_ice") + selectprint (PRINT_MEDIUM, " chills out with the Ice Imps!\n"); + if (attacker.classname == "monster_medusa") + if (attacker.skin==1) + selectprint (PRINT_MEDIUM, " was stricken by the beauty of the Crimson Medusa!\n"); + else + selectprint (PRINT_MEDIUM, " is helpless in the face of the Medusa's beauty!\n"); + if (attacker.classname == "monster_mezzoman") + selectprint (PRINT_MEDIUM, " is not yet worthy of facing the WereTiger!\n"); + if (attacker.classname == "monster_mummy") + selectprint (PRINT_MEDIUM, " got mummified!\n"); + if (attacker.classname == "monster_mummy_lord") + selectprint (PRINT_MEDIUM, " was escorted to the Underworld by a Mummy Lord!\n"); + if (attacker.classname == "monster_scorpion_black") + selectprint (PRINT_MEDIUM, " submits to the sting of the Black Scorpion!\n"); + if (attacker.classname == "monster_scorpion_yellow") + selectprint (PRINT_MEDIUM, " was poisoned by the fatal Golden Scorpion!\n"); + if (attacker.classname == "monster_skull_wizard") + selectprint (PRINT_MEDIUM, " succumbed to the Skull Wizard's magic!\n"); + if (attacker.classname == "monster_skull_wizard_lord") + selectprint (PRINT_MEDIUM, " was Skull-duggeried!\n"); + if (attacker.classname == "monster_snake") + selectprint (PRINT_MEDIUM, " was bitten by the lethal Cobra!\n"); + if (attacker.classname == "monster_spider_red_large") + selectprint (PRINT_MEDIUM, " was overcome by the Crimson Spiders!\n"); + if (attacker.classname == "monster_spider_red_small") + selectprint (PRINT_MEDIUM, " was eaten alive by the spiders!\n"); + if (attacker.classname == "monster_spider_yellow_large") + selectprint (PRINT_MEDIUM, " was overwhelmed by the Golden Spiders!\n"); + if (attacker.classname == "monster_spider_yellow_small") + selectprint (PRINT_MEDIUM, " is a meal for the spiders!\n"); + if (attacker.classname == "rider_famine") + selectprint(PRINT_MEDIUM, " was drained of life-force by Famine!\n"); + if (attacker.classname == "rider_death") + if(inflictor==attacker) + selectprint(PRINT_MEDIUM, " was snuffed out of existance by Death!\n"); + else if(inflictor.netname=="deathbone") + selectprint(PRINT_MEDIUM, " had his bones crushed to a fine powder by Death!\n"); + else if(iclass=="deathmissile") + selectprint(PRINT_MEDIUM, " was shot down by Death's crimson bolts!\n"); + else + selectprint(PRINT_MEDIUM, " was smitten by Death's unholy fire\n"); + if (attacker.classname == "rider_pestilence") + if(targ.deathtype=="poison") + selectprint(PRINT_MEDIUM, " was poisoned to death by Pestilence's Crossbow!\n"); + else + selectprint(PRINT_MEDIUM, "'s rotted corpse is the possession of Pestilence!\n"); + if (attacker.classname == "rider_war") + selectprint(PRINT_MEDIUM, " was taught the true meaning of War!\n"); + if (attacker.classname == "monster_eidolon") + if(inflictor==attacker) + selectprint(PRINT_MEDIUM, " was squashed like an insect by Eidolon!\n"); + else if(inflictor.classname=="eidolon fireball") + selectprint(PRINT_MEDIUM, " was obliterated by Eidolon's fireballs!\n"); + else if(inflictor.classname=="eidolon spell") + selectprint(PRINT_MEDIUM, " was introduced to a new level of pain by Eidolon's Magic!\n"); + else if(inflictor.classname=="eidolon flames") + selectprint(PRINT_MEDIUM, " was roasted to a crisp by Eidolon's Hellfire!\n"); + return; + } + + // tricks and traps + if(iclass=="solid wall") + { + selectprint(PRINT_MEDIUM, " was skewered on a spike!\n"); + return; + } + if(targ.decap==1) + { + if(targ.playerclass==CLASS_ASSASSIN||targ.playerclass==CLASS_SUCCUBUS) + selectprint(PRINT_MEDIUM, " should have quit while she was a head... oh, she IS a head!\n"); + else + selectprint(PRINT_MEDIUM, " should have quit while he was a head... oh, he IS a head!\n"); + return; + } + if(targ.decap==2) + { + if(targ.playerclass==CLASS_ASSASSIN||targ.playerclass==CLASS_SUCCUBUS) + selectprint(PRINT_MEDIUM, " got her head blown off!\n"); + else + selectprint(PRINT_MEDIUM, " got his head blown off!\n"); + return; + } + if(attacker.classname=="light_thunderstorm") + { + if(mapname=="eidolon") + selectprint(PRINT_MEDIUM, " was smited by Eidolon's unholy lightning!\n"); + else + selectprint(PRINT_MEDIUM, " shouldn't mess with Mother Nature!\n"); + return; + } + if(targ.deathtype=="zap") + { + selectprinti(PRINT_MEDIUM, STR_ELECTROCUTE); + return; + } + if(targ.deathtype=="chopped") + { + selectprinti(PRINT_MEDIUM, STR_SLICENDICE); + return; + } + if (attacker.solid == SOLID_BSP && attacker != world) + { + selectprinti (PRINT_MEDIUM, STR_SQUISHED); + return; + } + if (attacker.classname == "trap_shooter" || attacker.classname == "trap_spikeshooter") + { + selectprinti (PRINT_MEDIUM, STR_SPIKED); + if (attacker.enemy.classname == "player" && attacker.enemy != targ) + { + selectprint(PRINT_MEDIUM, " by "); + selectprintname(PRINT_MEDIUM, attacker.enemy); + attacker.enemy.frags += 1; + } + selectprint(PRINT_MEDIUM, "\n"); + return; + } + if (attacker.classname == "fireball") + { + selectprinti (PRINT_MEDIUM, STR_ATEALAVABALL); + return; + } + if (attacker.classname == "trigger_changelevel") + { + selectprinti (PRINT_MEDIUM, STR_TRIEDTOLEAVE); + return; + } + + // in-water deaths + rnum = targ.watertype; + if (rnum == -3) + { + if (random() < 0.5) + selectprinti (PRINT_MEDIUM, STR_TAKESDEEPBREATH); + else + selectprinti (PRINT_MEDIUM, STR_NEEDSGILLS); + return; + } + else if (rnum == -4) + { + if (random() < 0.5) + selectprinti (PRINT_MEDIUM, STR_GULPEDSLIME); + else + selectprinti (PRINT_MEDIUM, STR_CANTEXISTSLIME); + return; + } + else if (rnum == -5) + { + if (random() < 0.3) + selectprinti (PRINT_MEDIUM, STR_NEEDSCOLDSHOWER); + else if (random() < 0.5) + selectprinti (PRINT_MEDIUM, STR_LIKESITHOT); + else + selectprinti (PRINT_MEDIUM, STR_SMELLSBURNTHAIR); + return; + } + + // fell to their death? + if (targ.deathtype == "falling") + { + targ.deathtype = ""; + selectprinti (PRINT_MEDIUM, STR_CHUNKYSALSA); + return; + } + + // hell if I know; he's just dead!!! + selectprinti (PRINT_MEDIUM, STR_CEASEDTOFUNCTION); + } +}; + diff --git a/combat.hc b/combat.hc new file mode 100644 index 0000000..0b1ddbb --- /dev/null +++ b/combat.hc @@ -0,0 +1,161 @@ +/* + * $Header: /HexenWorld/Siege/COMBAT.hc 16 5/25/98 10:56p Mgummelt $ + */ +void(vector org, vector vel, float damage, entity victim) SpawnPuff; + +float MetalHitSound (float targettype) +{ +//entity found; + + if(targettype==THINGTYPE_FLESH) + { + sound (self, CHAN_WEAPON, "weapons/met2flsh.wav", 1, ATTN_NORM); + return TRUE; + } + else + { +// found=find(world,classname,"misc_ripples"); +// if(found) +// starteffect(CE_RIPPLE, found.origin,'0 0 0',HX_FRAME_TIME); + if(targettype==THINGTYPE_WOOD||targettype==THINGTYPE_DIRT) + { + sound (self, CHAN_WEAPON, "weapons/met2wd.wav", 1, ATTN_NORM); + return TRUE; + } + else if(targettype==THINGTYPE_METAL) + { + sound (self, CHAN_WEAPON, "weapons/met2met.wav", 1, ATTN_NORM); + return TRUE; + } + else if(targettype==THINGTYPE_BROWNSTONE||targettype==THINGTYPE_GREYSTONE) + { + sound (self, CHAN_WEAPON, "weapons/met2stn.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +} + + +/* +================ +FireMelee +================ +*/ +void FireMelee (float damage_base,float damage_mod,float attack_radius) +{ + vector source; + vector org; + float damg;//, backstab; + float chance,point_chance; + + makevectors (self.v_angle); + source = self.origin+self.proj_ofs; + traceline (source, source + v_forward*64, FALSE, self); + + if (trace_fraction == 1.0) + { + traceline (source, source + v_forward*64 - (v_up * 30), FALSE, self); // 30 down + + if (trace_fraction == 1.0) + { + traceline (source, source + v_forward*64 + v_up * 30, FALSE, self); // 30 up + + if (trace_fraction == 1.0) + return; + } + } + + org = trace_endpos + (v_forward * 4); + + if (trace_ent.takedamage) + { + //FIXME:Add multiplier for level and strength + if(self.playerclass==CLASS_PALADIN&&self.weapon==IT_WEAPON2&&!trace_ent.flags2&FL_ALIVE) + damage_base*=1.3; + + if(self.playerclass==CLASS_DWARF) + if(self.weapon==IT_WEAPON2&&!trace_ent.flags2&FL_ALIVE) + { + if(flammable(trace_ent)) + damage_base*=2.2; + else if(trace_ent.thingtype==THINGTYPE_DIRT) + damage_base*=1.5; + else + damage_base*=1.2; + } + else + damage_base*=1.2; + + +/* if(trace_ent.flags2&FL_ALIVE&&self.playerclass==CLASS_ASSASSIN)//!fov(self,trace_ent,90) + { + vector t_vf,m_vf; + makevectors(trace_ent.angles); + t_vf = v_forward; + makevectors(self.angles); + m_vf = v_forward; + makevectors(self.v_angle); + if(t_vf*m_vf>0.5)//facing generally the same direction + { + CreateRedFlash(trace_endpos); + damage_base=trace_ent.health*random(0.75,1.2); + if(damage_base>100) + damage_base = 100; + backstab=TRUE; + } + }*/ + + damg = random(damage_mod+damage_base,damage_base); + SpawnPuff (org, '0 0 0', damg,trace_ent); + T_Damage (trace_ent, self, self, damg); +/* if(backstab) + { + if(!trace_ent.flags2&FL_ALIVE) + centerprint(self,"Critical Hit Backstab!\n"); + else + centerprint(self,"Backstab!\n"); + }*/ + + if(trace_ent.thingtype==THINGTYPE_FLESH) + sound (self, CHAN_WEAPON, "weapons/slash.wav", 1, ATTN_NORM); + else if(!MetalHitSound(trace_ent.thingtype)) + sound (self, CHAN_WEAPON, "weapons/hitwall.wav", 1, ATTN_NORM); + + // Necromancer stands a chance of vampirically stealing health points + if (self.playerclass == CLASS_NECROMANCER) + { + if ((trace_ent.flags & FL_MONSTER) || (trace_ent.flags & FL_CLIENT)) + { + chance = self.level * .05; + + if (chance > random()) + { + point_chance = self.level; + point_chance *= random(); + if (point_chance < 1) + point_chance = 1; + + sound (self, CHAN_BODY, "weapons/drain.wav", 1, ATTN_NORM); + + self.health += point_chance; + if (self.health>self.max_health) + self.health = self.max_health; + } + } + } + } + else + { // hit wall + if(!MetalHitSound(trace_ent.thingtype)) + sound (self, CHAN_WEAPON, "weapons/hitwall.wav", 1, ATTN_NORM); + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_GUNSHOT); + WriteByte (MSG_BROADCAST, 1); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + } + +} + diff --git a/constant.hc b/constant.hc new file mode 100644 index 0000000..98592a9 --- /dev/null +++ b/constant.hc @@ -0,0 +1,805 @@ +/* + * $Header: /HexenWorld/Siege/constant.hc 74 6/01/98 2:49a Mgummelt $ + */ + +// +// constants +// + +float FALSE = 0; +float TRUE = 1; + +float HX_FRAME_TIME = 0.05; +float HX_FPS = 20; + +// edict.flags +float FL_FLY = 1; +float FL_SWIM = 2; +float FL_PUSH = 4; // Object is pushable +float FL_CLIENT = 8; // set for all client edicts +float FL_INWATER = 16; // for enter / leave water splash +float FL_MONSTER = 32; +float FL_GODMODE = 64; // player cheat +float FL_NOTARGET = 128; // player cheat +float FL_ITEM = 256; // extra wide size for bonus items +float FL_ONGROUND = 512; // standing on something +float FL_PARTIALGROUND = 1024; // not all corners are valid +float FL_WATERJUMP = 2048; // player jumping out of water +float FL_JUMPRELEASED = 4096; // for jump debouncing +float FL_FLASHLIGHT = 8192; // quake 2 thingy +float FL_ARTIFACTUSED = 16384; // an artifact was just used +float FL_MOVECHAIN_ANGLE = 32768; // when in a move chain, will update the angle +float FL_FIRERESIST = 65536; // resistant to fire and heat and lava +float FL_FIREHEAL = 131072; // healed by fire, heat, and lava +float FL_COLDHEAL = 524288; // healed by freezing +float FL_ARCHIVE_OVERRIDE = 1048576; // quake 2 thingy +float FL_CLASS_DEPENDENT = 2097152; // model will appear different to each player +float FL_SPECIAL_ABILITY1 = 4194304; // has 1st special ability +float FL_SPECIAL_ABILITY2 = 8388608; // has 2nd special ability + +//edict.flags2 +//FIXME: Shielded and small may be able to be determined by +//other means... +float FL2_ADJUST_MON_DAM = 1; //Do more damage to monsters +float FL_NODAMAGE = 2; //Special flag put on a missle to make it not do damage- used only by mezzoman +float FL_SMALL = 4; //Small enough to be crsuhed underfoot +float FL_ALIVE = 8; //Dead or alive. +float FL_FAKE_WATER = 16; //Fake water +float FL_SUMMONED = 32; //Summoned monster, stops it from precaching +float FL_LEDGEHOLD = 64; //Can realistically pull yourself up over ledges, etc. +float FL2_FADE_UP = 128; //Succ. +float FL2_HARDFALL = 256; //Hit hard- Siege +float FL_TORNATO_SAFE = 512; +float FL2_DEADMEAT = 1024; //Tagged for death +float FL_CHAINED = 2048; //Held by chains +float FL2_CROUCHED = 4096; +float FL2_CROUCH_TOGGLE = 8192; +float FL2_FIRERESIST = 16384; // resistant to fire and heat and lava +float FL2_WALLCLIMB = 32768; // can climb walls +float FL2_EXCALIBUR = 65536; // Using excalibur +float FL2_REPLACEMENT = 131072; // replacement throne rrom key +float FL2_POISONED = 262144; // healed by freezing +float FL2_HASKEY = 524288; +float FL2_PARRIED = 1048576; +float FL2_ONFIRE = 4194304; // on fire + +// edict.drawflags +float MLS_MASKIN = 7; // MLS: Model Light Style +float MLS_MASKOUT = 248; +float MLS_NONE = 0; +float MLS_FULLBRIGHT = 1; +float MLS_POWERMODE = 2; +float MLS_TORCH = 3; +float MLS_FIREFLICKER = 4; +float MLS_INVIS = 5; +//float MLS_INVIS = 6; +float MLS_ABSLIGHT = 7; +float SCALE_TYPE_MASKIN = 24; +float SCALE_TYPE_MASKOUT = 231; +float SCALE_TYPE_UNIFORM = 0; // Scale X, Y, and Z +float SCALE_TYPE_XYONLY = 8; // Scale X and Y +float SCALE_TYPE_ZONLY = 16; // Scale Z +float SCALE_ORIGIN_MASKIN = 96; +float SCALE_ORIGIN_MASKOUT = 159; +float SCALE_ORIGIN_CENTER = 0; // Scaling origin at object center +float SCALE_ORIGIN_BOTTOM = 32; // Scaling origin at object bottom +float SCALE_ORIGIN_TOP = 64; // Scaling origin at object top +float DRF_TRANSLUCENT = 128; + +// Artifact Flags +float AFL_CUBE_RIGHT = 1; +float AFL_CUBE_LEFT = 2; +float AFL_TORCH = 4; +float AFL_SUPERHEALTH = 8; + +// edict.movetype values +float MOVETYPE_NONE = 0; // never moves +//float MOVETYPE_ANGLENOCLIP = 1; +//float MOVETYPE_ANGLECLIP = 2; +float MOVETYPE_WALK = 3; // players only +float MOVETYPE_STEP = 4; // discrete, not real time unless fall +float MOVETYPE_FLY = 5; +float MOVETYPE_TOSS = 6; // gravity +float MOVETYPE_PUSH = 7; // no clip to world, push and crush +float MOVETYPE_NOCLIP = 8; +float MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters +float MOVETYPE_BOUNCE = 10; +float MOVETYPE_BOUNCEMISSILE = 11; // bounce with extra size and no gravity +float MOVETYPE_PUSHPULL = 13; // pushable/pullable object +float MOVETYPE_SWIM = 14; // object won't move out of water + +// particle types +float PARTICLETYPE_STATIC = 0; +float PARTICLETYPE_GRAV = 1; +float PARTICLETYPE_FASTGRAV = 2; +float PARTICLETYPE_SLOWGRAV = 3; +float PARTICLETYPE_FIRE = 4; +float PARTICLETYPE_EXPLODE = 5; +float PARTICLETYPE_EXPLODE2 = 6; +float PARTICLETYPE_BLOB = 7; +float PARTICLETYPE_BLOB2 = 8; +float PARTICLETYPE_RAIN = 9; +float PARTICLETYPE_C_EXPLODE = 10; +float PARTICLETYPE_C_EXPLODE2 = 11; +float PARTICLETYPE_SPIT = 12; +float PARTICLETYPE_FIREBALL = 13; +float PARTICLETYPE_ICE = 14; +float PARTICLETYPE_SPELL = 15; +//MISSION PACK +float PARTICLETYPE_DARKEN = 24; //Particle will darken to darkest color of that shade, valid only for colors <= 232 +float PARTICLETYPE_REDFIRE = 26; //Particle will darken to darkest color of that shade, valid only for colors <= 232 +float PARTICLETYPE_ACIDBALL = 27; //Built-in model trail +float PARTICLETYPE_BLUESTEP = 28; //Built-in model trail + +// Hexen hull constants +float HULL_IMPLICIT = 0; //Choose the hull based on bounding box- like in Quake +float HULL_POINT = 1; //0 0 0, 0 0 0 +float HULL_PLAYER = 2; //'-16 -16 0', '16 16 56' +float HULL_SCORPION = 3; //'-24 -24 -20', '24 24 20' +float HULL_CROUCH = 4; //'-16 -16 0', '16 16 28' +//Next 2 clip though world? +float HULL_HYDRA = 5; //'-28 -28 -24', '28 28 24' +float HULL_GOLEM = 6; //???,??? + +// Keep around old constants until all references are removed +float HULL_OLD = 0; +float HULL_SMALL = 1; +float HULL_NORMAL = 2; +float HULL_BIG = 3; + +// edict.solid values +float SOLID_NOT = 0; // no interaction with other objects +float SOLID_TRIGGER = 1; // touch on edge, but not blocking +float SOLID_BBOX = 2; // touch on edge, block +float SOLID_SLIDEBOX = 3; // touch on edge, but not an onground +float SOLID_BSP = 4; // bsp clip, touch on edge, block +float SOLID_PHASE = 5; // will interact with all objects except entities with FL_MONSTER & FL_CLIENT - those it will pass through + +// range values +float RANGE_MELEE = 0; +float RANGE_NEAR = 1; +float RANGE_MID = 2; +float RANGE_FAR = 3; + +// deadflag values + +float DEAD_NO = 0; +float DEAD_DYING = 1; +float DEAD_DEAD = 2; +float DEAD_RESPAWNABLE = 3; + +// takedamage values + +float DAMAGE_NO = 0; // Entity cannot be hurt +float DAMAGE_YES = 1; // Can be hurt +float DAMAGE_NO_GRENADE = 2; // Will not trigger a grenade to explode + + +// use inventory flags to show which item is the current item +float INV_NONE = 0; +float INV_TORCH = 1; +float INV_HP_BOOST = 2; +float INV_SUPER_HP_BOOST = 3; +float INV_MANA_BOOST = 4; +float INV_TELEPORT = 5; +float INV_TOME = 6; +float INV_SUMMON = 7; +float INV_INVISIBILITY = 8; +float INV_GLYPH = 9; +float INV_HASTE = 10; +float INV_BLAST = 11; +float INV_POLYMORPH = 12; +float INV_FLIGHT = 13; +float INV_CUBEOFFORCE = 14; +float INV_INVINCIBILITY = 15; + +float ARTIFACT_TORCH = 1; +float ARTIFACT_HP_BOOST = 2; +float ARTIFACT_SUPER_HP_BOOST = 3; +float ARTIFACT_MANA_BOOST = 4; +float ARTIFACT_TELEPORT = 5; +float ARTIFACT_TOME = 6; +float ARTIFACT_SUMMON = 7; +float ARTIFACT_INVISIBILITY = 8; +float ARTIFACT_GLYPH = 9; +float ARTIFACT_HASTE = 10; +float ARTIFACT_BLAST = 11; +float ARTIFACT_POLYMORPH = 12; +float ARTIFACT_FLIGHT = 13; +float ARTIFACT_CUBEOFFORCE = 14; +float ARTIFACT_INVINCIBILITY = 15; +float ARTIFACT_ARROWS = 16; +float ARTIFACT_GRENADES = 17; +float ARTIFACT_CLIMB = 18; + + +// Use ring flags to show which rings hero carries +float RING_NONE = 0; +float RING_FLIGHT = 1; +float RING_WATER = 2; +float RING_REGENERATION = 4; +float RING_TURNING = 8; + + +// Use artifact flags to show which artifacts are in use +float ART_NONE = 0; +float ART_HASTE = 1; +float ART_INVINCIBILITY = 2; +float ART_TOMEOFPOWER = 4; +float ART_INVISIBILITY = 8; +float ARTFLAG_FROZEN = 16; // 32 +float ARTFLAG_STONED = 32; // 64 +float ARTFLAG_DIVINE_INTERVENTION = 64; // 128 +float ART_CLIMB = 128; // 256 + + +// Gobal skin textures +float GLOBAL_SKIN_STONE = 100; +float GLOBAL_SKIN_ICE = 101; +float GLOBAL_SKIN_NOTEAM = 102;//just black + +// Player Classes +float CLASS_NONE = 0; +float CLASS_PALADIN = 1; +float CLASS_CRUSADER = 2; +float CLASS_NECROMANCER = 3; +float CLASS_ASSASSIN = 4; +//MP +float CLASS_SUCCUBUS = 5; +//Siege +float CLASS_DWARF = 6; + + +// Monster Classes +float CLASS_GRUNT = 1; +float CLASS_HENCHMAN = 2; +float CLASS_LEADER = 3; +float CLASS_BOSS = 4; +float CLASS_FINAL_BOSS = 5; + + +float MAX_HEALTH = 200; + +// Player Mode +float MODE_NORMAL = 0; // normal play mode +float MODE_CAMERA = 1; // player is a camera right now + +float AS_STRAIGHT = 1; +float AS_SLIDING = 2; +float AS_MELEE = 3; +float AS_MISSILE = 4; +float AS_WAIT = 5; +float AS_FERRY = 6; + +// Generic Weapon Names +float IT_WEAPON1 = 4096; +float IT_WEAPON2 = 1; +float IT_WEAPON3 = 2; +float IT_WEAPON4 = 4; +float IT_TESTWEAP = 8; +float IT_WEAPON4_1 = 16; // First half of weapon +float IT_WEAPON4_2 = 32; // Second half of weapon + + +// paladin weapons +float IT_GAUNTLETS = 4096; + + + +float IT_ARMOR1 = 8192; +float IT_ARMOR2 = 16384; +float IT_ARMOR3 = 32768; +float IT_SUPERHEALTH = 65536; + + +float IT_INVISIBILITY = 524288; +float IT_INVULNERABILITY = 1048576; +float IT_SUIT = 2097152; +float IT_QUAD = 4194304; + +// rings - amount of time they work +float FLIGHT_TIME = 30; +float WATER_TIME = 30; +float ABSORPTION_TIME = 30; +float REGEN_TIME = 30; +float TURNING_TIME = 30; + +// artifacts - amount of time they work +float HASTE_TIME = 15; +float TOME_TIME = 30; + +float RESPAWN_TIME = 30; + +// weapon damage values +float WEAPON1_BASE_DAMAGE = 12; +float WEAPON1_ADD_DAMAGE = 12; +float WEAPON1_PWR_BASE_DAMAGE = 30; +float WEAPON1_PWR_ADD_DAMAGE = 20; +float WEAPON1_PUSH = 5; + + +// glyph of the ancients +float GLYPH_BASE_DAMAGE = 100; +float GLYPH_ADD_DAMAGE = 20; + +// Modifier for HASTE +//float HASTE_MOD = 2; +float BLAST_RADIUS = 200; +float BLASTDAMAGE = 2; + +// Damage values for attacks from monsters +float DMG_ARCHER_PUNCH = 4; +float DMG_MUMMY_PUNCH = 8; +float DMG_MUMMY_BITE = 2; + + +//Thing Types +float THINGTYPE_GREYSTONE = 1; +float THINGTYPE_WOOD = 2; +float THINGTYPE_METAL = 3; +float THINGTYPE_FLESH = 4; +float THINGTYPE_FIRE = 5; +float THINGTYPE_CLAY = 6; +float THINGTYPE_LEAVES = 7; +float THINGTYPE_HAY = 8; +float THINGTYPE_BROWNSTONE = 9; +float THINGTYPE_CLOTH = 10; +float THINGTYPE_WOOD_LEAF = 11; +float THINGTYPE_WOOD_METAL = 12; +float THINGTYPE_WOOD_STONE = 13; +float THINGTYPE_METAL_STONE = 14; +float THINGTYPE_METAL_CLOTH = 15; +float THINGTYPE_WEBS = 16; +float THINGTYPE_GLASS = 17; +float THINGTYPE_ICE = 18; +float THINGTYPE_CLEARGLASS = 19; +float THINGTYPE_REDGLASS = 20; +float THINGTYPE_ACID = 21; +float THINGTYPE_METEOR = 22; +float THINGTYPE_GREENFLESH = 23; +float THINGTYPE_BONE = 24; +float THINGTYPE_DIRT = 25; + + +// point content values +float CONTENT_EMPTY = -1; +float CONTENT_SOLID = -2; +float CONTENT_WATER = -3; +float CONTENT_SLIME = -4; +float CONTENT_LAVA = -5; +float CONTENT_SKY = -6; + +float STATE_TOP = 0; +float STATE_BOTTOM = 1; +float STATE_UP = 2; +float STATE_DOWN = 3; +float STATE_MOVING = 4; + +vector VEC_ORIGIN = '0 0 0'; +vector VEC_HULL_MIN = '-16 -16 -24'; +vector VEC_HULL_MAX = '16 16 32'; +//Temp- because player models origins are at feet, +//Above values raise them 12 above the floor! +//But what about monsters using this Hull size?? +//vector VEC_HULL_MIN = '-16 -16 0'; +//vector VEC_HULL_MAX = '16 16 56'; + +vector VEC_HULL2_MIN = '-32 -32 -24'; +vector VEC_HULL2_MAX = '32 32 64'; + +// protocol bytes +float SVC_TEMPENTITY = 23; +float SVC_KILLEDMONSTER = 27; +float SVC_FOUNDSECRET = 28; +float SVC_INTERMISSION = 30; +float SVC_FINALE = 31; +float SVC_CDTRACK = 32; +float SVC_SELLSCREEN = 33; +float SVC_UPDATE_KINGOFHILL = 51;//MP +float SVC_SET_VIEW_TINT = 53; +float SVC_SET_VIEW_FLAGS = 56; +float SVC_CLEAR_VIEW_FLAGS = 57; +float SVC_MIDI_NAME = 65; + +// Client Effects +float CE_RAIN = 1; +float CE_FOUNTAIN = 2; +float CE_QUAKE = 3; +float CE_WHITE_SMOKE = 4; +float CE_BLUESPARK = 5; +float CE_YELLOWSPARK = 6; +float CE_SM_CIRCLE_EXP = 7; +float CE_BG_CIRCLE_EXP = 8; +float CE_SM_WHITE_FLASH = 9; +float CE_WHITE_FLASH = 10; +float CE_YELLOWRED_FLASH = 11; +float CE_BLUE_FLASH = 12; +float CE_SM_BLUE_FLASH = 13; +float CE_RED_FLASH = 14; +float CE_SM_EXPLOSION = 15; +float CE_LG_EXPLOSION = 16; +float CE_FLOOR_EXPLOSION = 17; +float CE_RIDER_DEATH = 18; +float CE_BLUE_EXPLOSION = 19; +float CE_GREEN_SMOKE = 20; +float CE_GREY_SMOKE = 21; +float CE_RED_SMOKE = 22; +float CE_SLOW_WHITE_SMOKE = 23; +float CE_REDSPARK = 24; +float CE_GREENSPARK = 25; +float CE_TELESMK1 = 26; +float CE_TELESMK2 = 27; +float CE_ICE_HIT = 28;// icehit.spr 0-5 +float CE_MEDUSA_HIT = 29;// medhit.spr 0-6 +float CE_MEZZO_REFLECT = 30;// mezzoref.spr 0-5 +float CE_FLOOR_EXPLOSION2 = 31;// flrexpl2.spr 0-19 +float CE_XBOW_EXPLOSION = 32;// xbowexpl.spr 0-16 +float CE_NEW_EXPLOSION = 33;// gen_expl.spr 0-13 +float CE_MAGIC_MISSILE_EXPLOSION = 34;// mm_expld.spr +float CE_GHOST = 35;// ghost.spr- translucent +float CE_BONE_EXPLOSION = 36;// bonexpld.spr +float CE_REDCLOUD = 37;// rcloud.spr +float CE_TELEPORTERPUFFS = 38; +float CE_TELEPORTERBODY = 39; +float CE_BONESHARD = 40; +float CE_BONESHRAPNEL = 41; +float CE_HWMISSILESTAR = 42; +float CE_HWEIDOLONSTAR = 43; +float CE_HWSHEEPINATOR = 44; +float CE_TRIPMINE = 45; +float CE_HWBONEBALL = 46; +float CE_HWRAVENSTAFF = 47; +float CE_TRIPMINESTILL = 48; +float CE_SCARABCHAIN = 49; +float CE_SM_EXPLOSION2 = 50; +float CE_HWSPLITFLASH = 51; +float CE_HWXBOWSHOOT = 52; +float CE_HWRAVENPOWER = 53; +float CE_HWDRILLA = 54; +float CE_DEATHBUBBLES = 55; +//MISSION PACK +float CE_RIPPLE = 56; +float CE_BLDRN_EXPL = 57; +float CE_ACID_MUZZFL = 58; +float CE_ACID_HIT = 59; +float CE_FIREWALL_SMALL = 60; +float CE_FIREWALL_MEDIUM = 61; +float CE_FIREWALL_LARGE = 62; +float CE_LBALL_EXPL = 63; +float CE_ACID_SPLAT = 64; +float CE_ACID_EXPL = 65; +float CE_FBOOM = 66; +float CE_BOMB = 67; +float CE_BRN_BOUNCE = 68; +float CE_LSHOCK = 69; +float CE_FLAMEWALL = 70; +float CE_FLAMEWALL2 = 71; +float CE_FLOOR_EXPLOSION3 = 72; +float CE_ONFIRE = 73; +float CE_FLAMESTREAM = 74; + + +// Temporary entities +float TE_SPIKE = 0; +float TE_SUPERSPIKE = 1; +float TE_GUNSHOT = 2; +float TE_EXPLOSION = 3; +float TE_TAREXPLOSION = 4; +float TE_LIGHTNING1 = 5; +float TE_LIGHTNING2 = 6; +float TE_WIZSPIKE = 7; +float TE_KNIGHTSPIKE = 8; +float TE_LIGHTNING3 = 9; +float TE_LAVASPLASH = 10; +float TE_TELEPORT = 11; +float TE_STREAM_CHAIN = 25; +float TE_STREAM_SUNSTAFF1 = 26; +float TE_STREAM_SUNSTAFF2 = 27; +float TE_STREAM_LIGHTNING = 28; +float TE_STREAM_COLORBEAM = 29; +float TE_STREAM_ICECHUNKS = 30; +float TE_STREAM_GAZE = 31; +float TE_STREAM_FAMINE = 32; + +float TE_BIGGRENADE = 33; +float TE_CHUNK = 34; +float TE_HWBONEPOWER = 35; +float TE_HWBONEPOWER2 = 36; +float TE_METEORHIT = 37; +float TE_HWRAVENDIE = 38; +float TE_HWRAVENEXPLODE = 39; +float TE_XBOWHIT = 40; +float TE_CHUNK2 = 41; +float TE_ICEHIT = 42; +float TE_ICESTORM = 43; +float TE_HWMISSILEFLASH = 44; +float TE_SUNSTAFF_CHEAP = 45; +float TE_LIGHTNING_HAMMER = 46; +float TE_DRILLA_EXPLODE = 47; +float TE_DRILLA_DRILL = 48; +float TE_HWTELEPORT = 49; +float TE_SWORD_EXPLOSION = 50; +float TE_AXE_BOUNCE = 51; +float TE_AXE_EXPLODE = 52; +float TE_TIME_BOMB = 53; +float TE_FIREBALL = 54; +float TE_SUNSTAFF_POWER = 55; +float TE_PURIFY2_EXPLODE = 56; +float TE_PLAYER_DEATH = 57; +float TE_PURIFY1_EFFECT = 58; +float TE_TELEPORT_LINGER = 59; +float TE_LINE_EXPLOSION = 60; +float TE_METEOR_CRUSH = 61; +//MP +float TE_STREAM_LIGHTNING_SMALL = 62; + +float TE_ACIDBALL = 63; +float TE_ACIDBLOB = 64; +float TE_FIREWALL = 65; +float TE_FIREWALL_IMPACT = 66; +float TE_HWBONERIC = 67; +float TE_POWERFLAME = 68; +float TE_BLOODRAIN = 69; +float TE_AXE = 70; +float TE_PURIFY2_MISSILE = 71; +float TE_SWORD_SHOT = 72; +float TE_ICESHOT = 73; +float TE_METEOR = 74; +float TE_LIGHTNINGBALL = 75; +float TE_MEGAMETEOR = 76; +float TE_CUBEBEAM = 77; +float TE_LIGHTNINGEXPLODE = 78; +float TE_ACID_BALL_FLY = 79; +float TE_ACID_BLOB_FLY = 80; +float TE_CHAINLIGHTNING = 81; + + + +// Stream flags +float STREAM_ATTACHED = 16; +float STREAM_TRANSLUCENT = 32; + + +// sound channels +// channel 0 never willingly overrides +// other channels (1-7) allways override a playing sound on that channel +float CHAN_AUTO = 0; +float CHAN_WEAPON = 1; +float CHAN_VOICE = 2; +float CHAN_ITEM = 3; +float CHAN_BODY = 4; +float CHAN_UPDATE = 7;// All sounds on this channel are updated by the EF_UPDATESOUND flag +//MP +float PHS_OVERRIDE_R = 8;//CHAN_????+PHS_OVERRIDE_R Forces the sound channel to be reliable and not use the PHS + +float SOUND_STARTED = 7777777;//Just used to keep track of whether I played a certain sound or not- 7777777 because t_dith is used as time+X elsewhere in code +float SOUND_STOPPED = 0;//clears out t_width fpr next playsound check + +float ATTN_NONE = 0; +float ATTN_NORM = 1; +float ATTN_IDLE = 2; +float ATTN_STATIC = 3; +//MP +float ATTN_LOOP = 4;//Sound will start on client even if volume is 0- so if player comes into range, it will be playing- attenuates like ATTN_NORM + +// update types +float UPDATE_GENERAL = 0; +float UPDATE_STATIC = 1; +float UPDATE_BINARY = 2; +float UPDATE_TEMP = 3; + +// entity effects +float EF_BRIGHTFIELD = 1; +float EF_MUZZLEFLASH = 2;//used for sword impacts and firing +float EF_BRIGHTLIGHT = 4;//used a lot +float EF_TORCHLIGHT = 6;//4 and 2? +float EF_DIMLIGHT = 8;//torch +float EF_DARKLIGHT = 16; +float EF_DARKFIELD = 32;//haste +float EF_LIGHT = 64;//small light field +float EF_NODRAW = 128;//invis +//end of first byte sent to clients + +//where is 256 and 512? +float EF_ONFIRE = 1024;//on fire +float EF_INVINC_CIRC = 16;//Succubus' invincibility effect +float EF_POWERFLAMEBURN = 2048; +float EF_POWERFLAME = 4096; +float EF_UPDATESOUND = 8192; + + +float EF_POISON_GAS = 2097152;//MP +float EF_ACIDBLOB = 4194304;//MP +//float EF_PURIFY2_EFFECT = 2097152; +//float EF_AXE_EFFECT = 4194304; +//float EF_SWORD_EFFECT = 8388608; +float EF_TORNADO_EFFECT = 16777216; +float EF_ICESTORM_EFFECT = 33554432; +//float EF_ICEBALL_EFFECT = 67108864; +//float EF_METEOR_EFFECT = 134217728; +float EF_HAMMER_EFFECTS = 268435456; +float EF_BEETLE_EFFECTS = 536870912; + +// messages +float MSG_BROADCAST = 0; // unreliable to all +float MSG_ONE = 1; // reliable to one (msg_entity) +float MSG_ALL = 2; // reliable to all +float MSG_INIT = 3; // write to the init string +float MSG_MULTICAST = 4; // for multicast() call + +// message levels +float PRINT_LOW = 0; // pickup messages +float PRINT_MEDIUM = 1; // death messages +float PRINT_HIGH = 2; // critical messages +float PRINT_CHAT = 3; // also goes to chat console + +// multicast sets +float MULTICAST_ALL = 0; // every client +float MULTICAST_PHS = 1; // within hearing +float MULTICAST_PVS = 2; // within sight +float MULTICAST_ALL_R = 3; // every client, reliable +float MULTICAST_PHS_R = 4; // within hearing, reliable +float MULTICAST_PVS_R = 5; // within sight, reliable + +float STEP_HEIGHT = 18; // Max step height + +// monster AI states +float AI_DECIDE = 0; // An action was just finished - time to decide what to do +float AI_STAND = 1; // Standing guard +float AI_WALK = 2; // Walking +float AI_CHARGE = 4; // Charging enemy +float AI_WANDER = 8; // Wandering around mindlessly +float AI_MELEE_ATTACK = 16; // +float AI_MISSILE_ATTACK = 32; // +float AI_MISSILE_REATTACK = 64; // Attacking again from attack stance (archer) +float AI_PAIN = 128; // Monster has only 1 type of pain +float AI_PAIN_CLOSE = 256; // Pain when close to enemy +float AI_PAIN_FAR = 512; // Pain when far from enemy +float AI_DEAD = 1024; // +float AI_TURNLOOK = 2048; // Turning to look for enemy +float AI_DEAD_GIB = 4096; // Can be gibbed when killed +float AI_DEAD_TWITCH = 8192; // Twitches while dead + +// Return values for AdvanceFrame() +float AF_NORMAL = 0; +float AF_BEGINNING = 1; +float AF_END = 2; + +float CHUNK_MAX = 30; // Max number of chunks (models) that can be alive at one time +float MAX_LEVELS = 10; + + +// server flags +float SFL_EPISODE_1 = 1; +float SFL_EPISODE_2 = 2; +float SFL_EPISODE_3 = 4; +float SFL_EPISODE_4 = 8; +float SFL_NEW_UNIT = 16; +float SFL_NEW_EPISODE = 32; +// = 64; +// = 128; +float SFL_CROSS_TRIGGER_1 = 256; +float SFL_CROSS_TRIGGER_2 = 512; +float SFL_CROSS_TRIGGER_3 = 1024; +float SFL_CROSS_TRIGGER_4 = 2048; +float SFL_CROSS_TRIGGER_5 = 4096; +float SFL_CROSS_TRIGGER_6 = 8192; +float SFL_CROSS_TRIGGER_7 = 16384; +float SFL_CROSS_TRIGGER_8 = 32768; + +float SFL_CROSS_TRIGGERS = 65280; +float attck_cnt; + +float WF_NORMAL_ADVANCE = 0; // States when using advanceweaponframe +float WF_CYCLE_STARTED = 1; +float WF_CYCLE_WRAPPED = 2; +float WF_LAST_FRAME = 3; + +float WORLDTYPE_CASTLE = 0; +float WORLDTYPE_EGYPT = 1; +float WORLDTYPE_MESO = 2; +float WORLDTYPE_ROMAN = 3; + +//Spawnflags for monster spawners +float IMP = 1; +float ARCHER = 2; +float WIZARD = 4; +float SCORPION = 8; +float SPIDER = 16; +float ONDEATH = 32; +float QUIET = 64; +float TRIGGERONLY = 128; + +//spawnflag for all monsters +float JUMP = 4; //Gives monster the ability to jump +float PLAY_DEAD = 8; //Makes a monster play dead at start +float NO_DROP = 32; //Keeps them from dropping to the ground at spawntime + +//spawnflag for items, weapons, artifacts +float FLOATING = 1; //Keeps them from dropping to the ground at spawntime + +//Spawnflags for barrels +float BARREL_DOWNHILL = 1; +float BARREL_NO_DROP = 2; +float ON_SIDE = 4; +float BARREL_SINK = 8; +float DROP_USE = 16;//Barrel won't drop unless used +float BARREL_RESPAWN = 32;//Upon death, barrel will respawn at it's initial origin +//Barrel types +float BARREL_UNBREAKABLE = 16; +float BARREL_NORMAL = 32; +float BARREL_EXPLODING = 64; +float BARREL_INDESTRUCTIBLE = 128; +float BARREL_GFIRE = 256; + +//For func_rotate +float GRADUAL = 32; +float TOGGLE_REVERSE = 64; +float KEEP_START = 128; + +float NO_RESPAWN = 0; // For the spawning of artifacts +float RESPAWN = 1; + +float RING_REGENERATION_MAX = 150; // Number of health points ring gives you back +float RING_FLIGHT_MAX = 60; // Number of seconds you can fly +float RING_WATER_MAX = 60; // Number of seconds you can stay under water +float RING_TURNING_MAX = 60; // Number of seconds you can turn missiles + +float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05- for camera +float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A- for camera + +//act_states - for player anim +float ACT_STAND = 0; +float ACT_RUN = 1; +float ACT_SWIM_FLY = 2; +float ACT_ATTACK = 3; +float ACT_PAIN = 4; +float ACT_JUMP = 5; +float ACT_CROUCH_STAND = 6; +float ACT_CROUCH_MOVE = 7; +float ACT_DEAD = 8; +float ACT_DECAP = 9; + +float XBOW_IMPACT_DEFAULT = 0; +float XBOW_IMPACT_GREENFLESH = 2; +float XBOW_IMPACT_REDFLESH = 4; +float XBOW_IMPACT_WOOD = 6; +float XBOW_IMPACT_STONE = 8; +float XBOW_IMPACT_METAL = 10; +float XBOW_IMPACT_ICE = 12; +float XBOW_IMPACT_MUMMY = 14; + +float DM_CAPTURE_THE_TOKEN = 1; +float DM_HUNTER = 2; +float DM_SIEGE = 3; + +float GF_HAS_TOKEN = 1; +float GF_HAS_LEFT_HUNTER = 2; + +//MISSION PACK +//for worldspawn +float MISSIONPACK = 1;//Spawnflag on world to use some mission-pack specific code for brush ents +float WSF_SIEGE = 2;//Spawnflag on world to use some mission-pack specific code for brush ents + +//SIEGE +float ST_DEFENDER = 1; +float ST_ATTACKER = 2; +float ACT_YAK_HIT = 2; +float ACT_YAK_HOWL = 9; + +float IT_WEAPON5 = 32; +float IT_WEAPON6 = 64; +float IT_WEAPON7 = 128; +float IT_WEAPON8 = 256; + +float WP_DEFENDERS = 10;//Defenders win pic +float WP_ATTCROWN = 11;//Attackers capture crown +float WP_ATTKILL = 12;//Attackers wipe out defenders + +float MAX_CLASS = 6;//Dwarf + +//Siege +float SVC_HASKEY = 79; // [byte] [byte] +float SVC_NONEHASKEY = 80; // [byte] [byte] +float SVC_ISDOC = 81; // [byte] [byte] +float SVC_NODOC = 82; // [byte] [byte] diff --git a/corpse.hc b/corpse.hc new file mode 100644 index 0000000..d5ebbf6 --- /dev/null +++ b/corpse.hc @@ -0,0 +1,107 @@ +/* + * $Header: /HexenWorld/Siege/Corpse.hc 5 6/01/98 2:49a Mgummelt $ + */ + + +void corpseblink (void) +{ + self.think = corpseblink; + thinktime self : 0.1; + self.scale -= 0.10; + + if (self.scale < 0.10) + remove(self); +} + +void init_corpseblink (void) +{ + CreateYRFlash(self.origin); + + self.drawflags (+) DRF_TRANSLUCENT | SCALE_TYPE_ZONLY | SCALE_ORIGIN_BOTTOM; + + corpseblink(); +} + +void() Spurt = +{ +float bloodleak; + + makevectors(self.angles); + bloodleak=rint(random(3,8)); + SpawnPuff (self.origin+v_forward*24+'0 0 -22', '0 0 -5'+ v_forward*random(20,40), bloodleak,self); + sound (self, CHAN_AUTO, "misc/decomp.wav", 0.3, ATTN_NORM); + if (self.lifetime < time||self.watertype==CONTENT_LAVA) + T_Damage(self,world,world,self.health); + else + { + self.think=Spurt; + thinktime self : random(0.5,6.5); + } +}; + +void () CorpseThink = +{ + self.think = CorpseThink; + thinktime self : 3; + + if (self.watertype==CONTENT_LAVA) // Corpse fell in lava + T_Damage(self,self,self,self.health); + else if (self.lifetime < time) // Time is up, begone with you + init_corpseblink(); +}; + +/* + * This uses entity.netname to hold the head file (for CorpseDie()) + * hack so that we don't have to set anything outside this function. + */ +void()MakeSolidCorpse = +{ +vector newmaxs; +// Make a gibbable corpse, change the size so we can jump on it + +//Won't be necc to pass headmdl once everything has it's .headmodel +//value set in spawn + self.th_die = chunk_death; + self.touch = obj_push; + self.health = random(10,25); + self.takedamage = DAMAGE_YES; + self.solid = SOLID_PHASE; + self.experience_value = 0; + if(self.classname!="monster_hydra") + self.movetype = MOVETYPE_STEP;//Don't get in the way + if(!self.mass) + self.mass=1; + +//To fix "player stuck" probem + newmaxs=self.maxs; + if(newmaxs_z>5) + newmaxs_z=5; + setsize (self, self.mins,newmaxs); + + if(self.flags&FL_ONGROUND) + self.velocity='0 0 0'; + self.flags(-)FL_MONSTER; + self.controller = self; + self.onfire = FALSE; + + pitch_roll_for_slope('0 0 0'); + + if ((self.decap) && (self.classname == "player")) + { + if (deathmatch||teamplay) + self.lifetime = time + random(20,40); // decompose after 40 seconds + else + self.lifetime = time + random(10,20); // decompose after 20 seconds + + self.owner=self; + self.think=Spurt; + thinktime self : random(1,4); + } + else + { + self.lifetime = time + random(10,20); // disappear after 20 seconds + self.think=CorpseThink; + thinktime self : 0; + } +}; + diff --git a/crossbow.hc b/crossbow.hc new file mode 100644 index 0000000..63eb6fa --- /dev/null +++ b/crossbow.hc @@ -0,0 +1,481 @@ +/* + * $Header: /HexenWorld/Siege/crossbow.hc 38 6/16/98 12:00p Ggribb $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\crossbow\final\crossbow.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\crossbow\final +$origin 0 0 0 +$base base skin +$skin skin +$flags 0 + +// +$frame select1 select2 select3 select4 select5 +$frame select6 select7 select8 select9 select10 +$frame select11 select12 select13 select14 select15 + +// +$frame shoot1 shoot2 shoot3 shoot4 shoot5 +$frame shoot6 shoot7 shoot8 shoot9 shoot10 +$frame shoot11 shoot12 shoot13 shoot14 shoot15 +$frame shoot16 shoot17 shoot18 shoot19 + +void flashspin () +{ + if(self.lifetime200&&other.thingtype!=THINGTYPE_FLESH)//So it can't break catapults and ballistas and ramparts + hitdmg=1; + + sound(self,CHAN_BODY,"misc/null.wav",1,ATTN_NORM); + setsize(self,'0 0 0','0 0 0'); + self.takedamage=DAMAGE_NO; + self.velocity='0 0 0'; + self.movetype=MOVETYPE_NOCLIP; + self.solid=SOLID_NOT; + self.touch=SUB_Null; + self.health=other.health; + + if(other.thingtype==THINGTYPE_FLESH) + sound(self, CHAN_WEAPON, "assassin/arr2flsh.wav", 1, ATTN_NORM); + else if(other.thingtype==THINGTYPE_WOOD) + sound(self, CHAN_WEAPON, "assassin/arr2wood.wav", 1, ATTN_NORM); + else + sound(self, CHAN_WEAPON, "weapons/met2stn.wav", 1, ATTN_NORM); + + MakeFlash(self.origin-v_forward*8); + + if(other.takedamage) + { + if(other.solid!=SOLID_BSP) + if(self.frags) + if(flammable(other)) + spawn_burner(other,FALSE); + + if(other.flags2&FL_ALIVE&&other.classname!="player_sheep") + { + headdist=vlen(other.origin+other.view_ofs - self.origin); + hitspot=self.origin+v_forward*headdist; + if(vlen(hitspot-self.origin)<10)//head shot, instant kill + { + T_Damage(other,self,self.owner,other.health+30); + skiprest=TRUE; + } + } + + if(!skiprest) + if(self.classname=="bolt") + { + if(other.thingtype==THINGTYPE_FLESH||other.classname=="barrel") + T_Damage(other,self,self.owner,hitdmg); + else + T_Damage(other,self,self.owner,random(2,5)); + } + else + T_Damage(other,self,self.owner,3); + SpawnPuff(self.origin+v_forward*8,'0 0 0'-v_forward*24,10,other); + if(other.solid!=SOLID_BSP) + { +//Put it right below view of player + if(other.classname=="player") + { + stickdir_z=other.origin_z+other.proj_ofs_z+ 1; + stickdir=other.origin+normalize(self.origin-other.origin)*12; + stick=TRUE; + setorigin(self,stickdir); + } + else + { + rad=(other.maxs_x+other.maxs_z)*0.5; + center=(other.absmax+other.absmin)*0.5; + stickspot=self.origin+v_forward*other.maxs_x*2; + if(vlen(center-stickspot)9) + self.frame=0; + } + if(self.lifetimetime) + { + missile.frags=TRUE; + missile.thingtype=THINGTYPE_METAL; + setmodel(missile,"models/flaming.mdl"); + missile.speed=random(1100,1400); + missile.classname="flarrow"; + missile.drawflags(+)MLS_ABSLIGHT|MLS_FIREFLICKER; + missile.abslight = .75; + } + else + { + missile.classname="bolt"; + missile.thingtype=THINGTYPE_WOOD_METAL; + setmodel(missile,"models/arrow.mdl"); + speed_mod=melee_dmg_mod_for_strength (self.strength); + missile.speed=random(1100,1400); + } + } + else + { + missile.classname="bolt"; + missile.thingtype=THINGTYPE_WOOD; + setmodel(missile,"models/arrow.mdl"); + speed_mod=melee_dmg_mod_for_strength (self.strength); + missile.speed=800+100*(random(speed_mod)); + } + missile.movetype=MOVETYPE_FLYMISSILE; + missile.th_die=chunk_death; + missile.touch=CB_BoltHit; +float num_weap; + num_weap=num_for_weap (self.weapon); + offset = rate_and_acc_for_weap [(self.playerclass - 1)*6+(num_weap - 1)*2+1]/2; + + v_offset = v_right*(random(offset)*2 - offset) + v_up*(random(offset)*2 - offset) + v_forward; + v_offset = normalize(v_offset); + missile.o_angle=missile.velocity=normalize(v_offset)*missile.speed; + missile.angles=vectoangles(missile.velocity); + + if(!powered_up) + { + missile.think = Missile_Arc; + thinktime missile : 0.2; + } +// missile.lifetime=time+0.2; + + setsize(missile,'0 0 0','0 0 0'); + setorigin(missile,self.origin+self.proj_ofs+v_forward*8); +}; + +void()crossbow_fire; +void crossbow_idle(void) +{ + self.th_weapon=crossbow_idle; + self.weaponframe=$shoot19; +} + +void crossbow_fire (void) +{ +float num_weap; + self.wfs = advanceweaponframe($shoot1,$shoot18); + self.th_weapon=crossbow_fire; + if(self.button0&&self.weaponframe==$shoot2 &&self.weapon==IT_WEAPON3) + self.weaponframe=$shoot1; + else if (self.weaponframe == $shoot2) + { + num_weap = num_for_weap (self.weapon); + if(self.playerclass==CLASS_ASSASSIN&&self.weapon==IT_WEAPON3) + { + sound(self,CHAN_WEAPON,"assassin/firefblt.wav",1,ATTN_NORM); + FireCB_Bolt(TRUE); + self.attack_finished=time+2;//rate_and_acc_for_weap[(self.playerclass - 1)*6+(num_weap - 1)*2]; + } + else + { + sound(self,CHAN_WEAPON,"assassin/firebolt.wav",1,ATTN_NORM); + FireCB_Bolt(FALSE); + self.attack_finished=time+rate_and_acc_for_weap[(self.playerclass - 1)*6+(num_weap - 1)*2]; + } + } + else if (self.wfs==WF_CYCLE_WRAPPED) + crossbow_idle(); +} + +void crossbow_select (void) +{ +//selection sound? + self.wfs = advanceweaponframe($select15,$select1); + self.weaponmodel = "models/xbow2.mdl"; + self.th_weapon=crossbow_select; + if (self.weaponframe==$select1) + { + self.attack_finished = time - 1; + crossbow_idle(); + } +} + +void crossbow_deselect (void) +{ + self.wfs = advanceweaponframe($select1,$select15); + self.th_weapon=crossbow_deselect; + if (self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + diff --git a/crusader.hc b/crusader.hc new file mode 100644 index 0000000..88afcad --- /dev/null +++ b/crusader.hc @@ -0,0 +1,385 @@ +/* + * $Header: /HexenWorld/Siege/crusader.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\players\crusader\final\crusader.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\players\crusader\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame crouch1 crouch2 crouch3 crouch4 crouch5 +$frame crouch6 crouch7 crouch8 crouch9 crouch10 +$frame crouch11 crouch12 crouch13 crouch14 crouch15 +$frame crouch16 crouch17 crouch18 crouch19 crouch20 + +// +$frame decap1 decap2 decap3 decap4 decap5 +$frame decap6 decap7 decap8 decap9 decap10 +$frame decap11 decap12 decap13 decap14 decap15 +$frame decap16 decap17 decap18 decap19 decap20 +$frame decap21 decap22 decap23 decap24 decap25 +$frame decap26 decap27 decap28 + +// +$frame die1 die2 die3 die4 die5 +$frame die6 die7 die8 die9 die10 +$frame die11 die12 die13 die14 die15 +$frame die16 die17 die18 die19 die20 + +// +$frame FINLPOLY + +// +$frame HmrFly1 HmrFly2 HmrFly3 HmrFly4 HmrFly5 +$frame HmrFly6 HmrFly7 HmrFly8 HmrFly9 HmrFly10 +$frame HmrFly11 HmrFly12 HmrFly13 HmrFly14 HmrFly15 + +// +$frame HmrHit1 HmrHit2 HmrHit3 HmrHit4 HmrHit5 +$frame HmrHit6 HmrHit7 HmrHit8 HmrHit9 HmrHit10 + +// +$frame hmrPain1 hmrPain2 hmrPain3 hmrPain4 hmrPain5 +$frame hmrPain6 hmrPain7 hmrPain8 + +// +$frame HmrStn1 HmrStn2 HmrStn3 HmrStn4 HmrStn5 +$frame HmrStn6 HmrStn7 HmrStn8 HmrStn9 HmrStn10 +$frame HmrStn11 HmrStn12 HmrStn13 + +// +$frame HmrRun1 HmrRun2 HmrRun3 HmrRun4 HmrRun5 +$frame HmrRun6 HmrRun7 HmrRun8 HmrRun9 HmrRun10 +$frame HmrRun11 HmrRun12 + +// +$frame IceFly1 IceFly2 IceFly3 IceFly4 IceFly5 +$frame IceFly6 IceFly7 IceFly8 IceFly9 IceFly10 +$frame IceFly11 IceFly12 IceFly13 IceFly14 IceFly15 + +// +$frame IcePain1 IcePain2 IcePain3 IcePain4 IcePain5 +$frame IcePain6 IcePain7 IcePain8 + +// +$frame IceRun1 IceRun2 IceRun3 IceRun4 IceRun5 +$frame IceRun6 IceRun7 IceRun8 IceRun9 IceRun10 +$frame IceRun11 IceRun12 + +// +$frame IceShot1 IceShot2 IceShot3 IceShot4 + +// +$frame IceStn1 IceStn2 IceStn3 IceStn4 IceStn5 +$frame IceStn6 IceStn7 IceStn8 IceStn9 IceStn10 +$frame IceStn11 IceStn12 IceStn13 + +// +$frame jump1 jump2 jump3 jump4 jump5 +$frame jump6 jump7 jump8 jump9 jump10 +$frame jump11 jump12 jump13 + +// +$frame SunFly1 SunFly2 SunFly3 SunFly4 SunFly5 +$frame SunFly6 SunFly7 SunFly8 SunFly9 SunFly10 +$frame SunFly11 SunFly12 SunFly13 SunFly14 + +// +$frame SunPain1 SunPain2 SunPain3 SunPain4 SunPain5 +$frame SunPain6 SunPain7 SunPain8 + +// +$frame SunRun1 SunRun2 SunRun3 SunRun4 SunRun5 +$frame SunRun6 SunRun7 SunRun8 SunRun9 SunRun10 +$frame SunRun11 SunRun12 + +// +$frame SunShot1 SunShot2 SunShot3 SunShot4 SunShot5 + +// +$frame SunStn1 SunStn2 SunStn3 SunStn4 SunStn5 +$frame SunStn6 SunStn7 SunStn8 SunStn9 SunStn10 +$frame SunStn11 SunStn12 SunStn13 + +/*-------------------------- +ACTUAL (UNIQUE TO CLASS) PLAYER CODE +----------------------------*/ +void() player_crusader_run; +void() player_crusader_crouch_stand; +void() player_crusader_crouch_move; +void() player_crusader_stand; + +void() player_crusader_jump=[++$jump1..$jump13]//FIX +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_crusader_swim = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel<3) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_crusader_hammer_swim =[++$HmrFly1..$HmrFly15] +{ + player_crusader_swim(); +}; + +void() player_crusader_sunstaff_swim =[++$SunFly1..$SunFly14] +{ + player_crusader_swim(); +}; + +void() player_crusader_ice_swim =[++$IceFly1..$IceFly15] +{ + player_crusader_swim(); +}; + +void() player_crusader_fly = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype!=MOVETYPE_FLY) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_crusader_hammer_fly =[++$HmrFly1..$HmrFly15] +{ + player_crusader_fly(); +}; + +void() player_crusader_sunstaff_fly =[++$SunFly1..$SunFly14] +{ + player_crusader_fly(); +}; + +void() player_crusader_ice_fly =[++$IceFly1..$IceFly15] +{ + player_crusader_fly(); +}; + +void() player_crusader_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_crusader_crouch_stand; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (self.velocity_x || self.velocity_y) + self.think=self.th_run; +}; + +void() player_crusader_hammer_stand =[++$HmrStn1..$HmrStn13] +{ + player_crusader_stand(); +}; + +void() player_crusader_sunstaff_stand =[++$SunStn1..$SunStn13] +{ + player_crusader_stand(); +}; + +void() player_crusader_ice_stand =[++$IceStn1..$IceStn13] +{ + player_crusader_stand(); +}; + +void() player_crusader_run = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_crusader_crouch_move; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; +}; + +void() player_crusader_hammer_run =[++$HmrRun1..$HmrRun12] +{ + player_crusader_run(); +}; + +void() player_crusader_sunstaff_run =[++$SunRun1..$SunRun12] +{ + player_crusader_run(); +}; + +void() player_crusader_ice_run =[++$IceRun1..$IceRun12] +{ + player_crusader_run(); +}; + +void() player_crusader_crouch_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.frame>$crouch20 || self.frame<$crouch1) + self.frame=$crouch1; + if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_stand; + else if (self.velocity_x || self.velocity_y) + self.think=player_crusader_crouch_move; + self.nextthink=time + HX_FRAME_TIME; +}; + +void() player_crusader_crouch_move =[++$crouch1..$crouch20] +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.movetype==MOVETYPE_FLY) + self.think=player_crusader_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_run; + else if (!self.velocity_x && !self.velocity_y) + self.think=player_crusader_crouch_stand; +}; + +void() player_crusader_attack= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped&&!self.button0) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_crusader_hammer_attack=[++$HmrHit1..$HmrHit10] +{ + player_crusader_attack(); +}; + +void() player_crusader_ice_attack=[++$IceShot1..$IceShot4] +{ + player_crusader_attack(); +}; + +void() player_crusader_sunstaff_attack=[++$SunShot1..$SunShot5] +{ + player_crusader_attack(); +}; + +void() player_crusader_pain= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_crusader_hammer_pain =[++$HmrPain1..$HmrPain8] +{ + if(self.frame==$HmrPain1) + PainSound(); + player_crusader_pain(); +}; + +void() player_crusader_sunstaff_pain =[++$SunPain1..$SunPain8] +{ + if(self.frame==$SunPain1) + PainSound(); + player_crusader_pain(); +}; + +void() player_crusader_ice_pain =[++$IcePain1..$IcePain8] +{ + if(self.frame==$IcePain1) + PainSound(); + player_crusader_pain(); +}; + +void() player_crusader_die1=[++$die1..$die20] +{ + if(cycle_wrapped) + { + self.frame=$die20; + self.think=PlayerDead; + } +}; + +void() player_crusader_behead = +{ + self.level=$decap1; + self.dmg=$decap28; + self.cnt=0; + player_behead(); +}; + +void Cru_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1) + { + self.th_stand=player_crusader_hammer_stand; + self.th_missile=player_crusader_hammer_attack; + self.th_run=player_crusader_hammer_run; + self.th_pain=player_crusader_hammer_pain; + self.th_swim=player_crusader_hammer_swim; + self.th_fly=player_crusader_hammer_fly; + } + else if(self.weapon==IT_WEAPON2) + { + self.th_stand=player_crusader_ice_stand; + self.th_missile=player_crusader_ice_attack; + self.th_run=player_crusader_ice_run; + self.th_pain=player_crusader_ice_pain; + self.th_swim=player_crusader_ice_swim; + self.th_fly=player_crusader_ice_fly; + } + else + { + self.th_stand=player_crusader_sunstaff_stand; + self.th_missile=player_crusader_sunstaff_attack; + self.th_run=player_crusader_sunstaff_run; + self.th_pain=player_crusader_sunstaff_pain; + self.th_swim=player_crusader_sunstaff_swim; + self.th_fly=player_crusader_sunstaff_fly; + } + if(self.hull!=HULL_CROUCH) + self.think=self.th_stand; +} diff --git a/cube.hc b/cube.hc new file mode 100644 index 0000000..4c7fcc8 --- /dev/null +++ b/cube.hc @@ -0,0 +1,282 @@ +/* + * $Header: /HexenWorld/Siege/cube.hc 4 5/25/98 1:38p Mgummelt $ + */ + + +float cube_distance = 500; + +void CubeDie(void) +{ + self.owner.artifact_flags(-)self.artifact_flags; + remove(self); +} + +float cube_find_target(void) +{ + entity item; + + item = findradius(self.origin, cube_distance); + + while (item) + { + if ((item.flags & FL_MONSTER) || ((item.classname == "player") && deathmatch == 1) && item.health > 0) + { + tracearea (self.origin,item.origin,self.mins,self.maxs,FALSE,self); + if (trace_ent == item) + { + if (!item.effects & EF_NODRAW) + { + self.enemy = item; + return TRUE; + } + } + } + + item = item.chain; + } + + return FALSE; +} + + +void do_fireball(vector offset); + +vector CubeDirection[6] = +{ + '90 0 0', + '-90 0 0', + '0 90 0', + '0 -90 0', + '0 0 90', + '0 0 -90' +}; + +void cube_fire(void) +{ +// float RanVal; + float Distance; + entity temp; + + if (time > self.monster_duration || self.owner.health <= 0 || self.shot_cnt >= 10) + { + CubeDie(); + return; + } + + if (!self.enemy) + { + self.cnt += 1; + if (self.cnt > 5) + { + cube_find_target(); + self.cnt = 0; + } + } + + if (self.enemy) + { + if (self.enemy.health <= 0) + { + self.enemy = world; + //self.drawflags (+) DRF_TRANSLUCENT; + } + } + + if (self.enemy) + { + if (random() < .7) + { + Distance = vlen(self.origin - self.enemy.origin); + if (Distance > cube_distance*2) + { + self.enemy = world; + //self.drawflags (+) DRF_TRANSLUCENT; + } + else + { + // Got to do this otherwise tracearea sees right through you + temp = self.owner; + self.owner = self; + + tracearea (self.origin,self.enemy.origin,self.mins,self.maxs,FALSE,self); + if (trace_ent == self.enemy) + { + self.adjust_velocity = CubeDirection[random(0,5)]; + self.abslight = 1; + + self.shot_cnt += 1; + + do_fireball('0 0 0'); + } + else + { + self.enemy = world; + //self.drawflags (+) DRF_TRANSLUCENT; + } + + self.owner = temp; + } + } + } +} + +void cube_rotate(void) +{ + vector NewOffset; + + NewOffset = concatv(self.adjust_velocity,'5 5 5'); + + self.adjust_velocity -= NewOffset; + self.v_angle += NewOffset; +} + +vector CubeFollowRate = '14 14 14'; +vector CubeAttackRate = '3 3 3'; + +void CubeThinkerB(void) +{ + vector NewSpot; + float Distance; + thinktime self : 0.05; + + if (!self.owner.flags2 & FL_ALIVE) + { + CubeDie(); + return; + } + + if (self.adjust_velocity == '0 0 0') + { + cube_fire(); + if (self.adjust_velocity == '0 0 0') + { + if (random() < 0.02) + { + self.adjust_velocity = CubeDirection[random(0,5)]; + } + } + } + cube_rotate(); + + if (self.abslight > .1) + self.abslight -= 0.1; + + self.angles = self.owner.angles + self.v_angle; + + self.count += random(4,6); + if (self.count > 360) + { + self.count -= 360; + } + + Distance = vlen(self.origin - self.owner.origin); + if (Distance > cube_distance) + { + self.enemy = world; + //self.drawflags (+) DRF_TRANSLUCENT; + } + + if (self.enemy != world) + { + NewSpot = self.enemy.origin + self.enemy.view_ofs; + + if (self.artifact_flags & AFL_CUBE_LEFT) + { + NewSpot += (cos(self.count) * 40 * '1 0 0') + (sin(self.count) * 40 * '0 1 0'); + } + else + { + NewSpot += (sin(self.count) * 40 * '1 0 0') + (cos(self.count) * 40 * '0 1 0'); + } + + self.movedir_z += random(10,12); + if (self.movedir_z > 360) + { + self.movedir_z -= 360; + } + + NewSpot_z += sin(self.movedir_z) * 10; + + NewSpot = self.origin + concatv(NewSpot - self.origin, CubeAttackRate); + } + else + { + makevectors(self.owner.v_angle); + + if (self.artifact_flags & AFL_CUBE_LEFT) + { + NewSpot = self.owner.origin + self.owner.view_ofs + '0 0 10' + v_factor('40 60 0'); + } + else + { + NewSpot = self.owner.origin + self.owner.view_ofs + '0 0 10' + v_factor('-40 60 0'); + } + + self.movedir_z += random(10,12); + if (self.movedir_z > 360) + { + self.movedir_z -= 360; + } + + NewSpot += (v_right * cos(self.count) * 15) + (v_up * sin(self.count) * 15) + + (v_forward * sin(self.movedir_z) * 15); + + NewSpot = self.origin + concatv(NewSpot - self.origin, CubeFollowRate); + } + + setorigin(self,NewSpot); +} + +void UseCubeOfForce(void) +{ + entity cube; + + if ((self.artifact_flags & AFL_CUBE_LEFT) && + (self.artifact_flags & AFL_CUBE_RIGHT)) + { // Already got two running + return; + } + + cube = spawn(); + + cube.owner = self; + cube.solid = SOLID_SLIDEBOX; + cube.movetype = MOVETYPE_NOCLIP;//MOVETYPE_FLY; + cube.flags (+) FL_FLY | FL_NOTARGET; + setorigin (cube, cube.owner.origin); + setmodel (cube, "models/cube.mdl"); + setsize (cube, '-5 -5 -5', '5 5 5'); + + cube.classname = "cube_of_force"; + cube.health = 10; + cube.dmg = -1; + + if (self.artifact_flags & AFL_CUBE_LEFT) + { + self.artifact_flags (+) AFL_CUBE_RIGHT; + cube.artifact_flags (+) AFL_CUBE_RIGHT; + } + else + { + self.artifact_flags (+) AFL_CUBE_LEFT; + cube.artifact_flags (+) AFL_CUBE_LEFT; + } + cube.think = CubeThinkerB; + cube.th_die = CubeDie; + + thinktime cube : 0.01; + cube.monster_duration = time + 45; + cube.shot_cnt = 0; + + cube.movedir = '100 100 0'; + cube.count = random(360); + self.movedir_z = random(360); + +// cube.drawflags (+) DRF_TRANSLUCENT; + cube.drawflags (+) MLS_ABSLIGHT; + + cube.abslight = .1; + + self.cnt_cubeofforce -= 1; +} + diff --git a/damage.hc b/damage.hc new file mode 100644 index 0000000..ebaa7ad --- /dev/null +++ b/damage.hc @@ -0,0 +1,1308 @@ +/* + * $Header: /HexenWorld/Siege/damage.hc 41 6/01/98 2:49a Mgummelt $ + */ + +void() T_MissileTouch; +void() info_player_start; +void necromancer_sphere(entity ent); +void crusader_sphere(entity ent); + +void() monster_death_use; +void(float damage, vector dir)PlayerDie; +void MonsterDropStuff(void); +void Use_TeleportCoin(void); +void UseInvincibility(void); +void Use_TomeofPower(void); +void use_super_healthboost(); + +float hitpoint_table[30] = +{ + 70, 85, // Paladin + 0, 0, 0, + + 65, 75, // Crusader + 0, 0, 0, + + 65, 75, // Necromancer + 0, 0, 0, + + 65, 75, // Assassin + 0, 0, 0, + + 65, 75, // Succubus + 0, 0, 0, + + 90, 100, // Dwarf + 0, 0, 0 +}; + +entity FindExpLeader() +{ +entity lastent, leader; +float top_exp; + lastent=nextent(world); + num_players=0; + while(lastent) + { + if(lastent.classname=="player") + { + num_players+=1; + if(lastent.experience>top_exp) + { + leader=lastent; + top_exp=leader.experience; + } + } + lastent=find(lastent,classname,"player"); + } + return leader; +} + +float flammable (entity toast) +{ + if(toast.health>0) + if(toast.thingtype==THINGTYPE_WOOD|| + toast.thingtype==THINGTYPE_FLESH|| + toast.thingtype==THINGTYPE_LEAVES|| + toast.thingtype==THINGTYPE_HAY|| + toast.thingtype==THINGTYPE_CLOTH|| + toast.thingtype==THINGTYPE_WOOD_LEAF|| + toast.thingtype==THINGTYPE_WOOD_METAL|| + toast.thingtype==THINGTYPE_WOOD_STONE|| + toast.thingtype==THINGTYPE_METAL_CLOTH|| + toast.thingtype==THINGTYPE_WEBS) + return TRUE; + return FALSE; +} + +void burner_think () +{ + if(self.lifetimeself.enemy.max_health) + self.enemy.health=self.enemy.max_health; + } + else + { + T_Damage(self.enemy,self,self.owner,self.enemy.fire_damage + random(1)); + } + } +} + +void spawn_burner (entity loser,float gfire) +{ + if (loser.flags2 & FL2_ONFIRE) + { + loser.fire_damage += 2; + return; + } + + if (coop && loser.classname == "player" && loser.team == self.owner.team && teamplay) + return; + + if(loser.netname=="obj_barrel_gfire") + { + if(loser.frame==0) + {//start up a greek fire barrel + entity oself; + oself=self; + self=loser; + loser.use(); + self=oself; + } + return; + } + + loser.fire_damage = 2; + + entity burner; + burner=spawn(); + burner.owner=self.owner; + burner.enemy=loser; + burner.think=burner_think; + burner.effects (+) EF_NODRAW; + burner.enemy.effects (+) EF_DIMLIGHT; + thinktime burner : 0; + burner.enemy.flags2 (+) FL2_ONFIRE; + burner.enemy.effects (+) EF_ONFIRE; + if(gfire) + { + burner.frags=TRUE;//Water has no effect! Yer screwed, pal! + burner.lifetime=time+random(10)+20; + } + else if(self.classname=="flarrow") + burner.lifetime=time+random(5)+5; + else + burner.lifetime=time+random(3)+3; +// if(burner.enemy.thingtype!=THINGTYPE_FLESH) +// burner.enemy.fire_damage/=2; + sound (burner.enemy, CHAN_AUTO, "misc/combust.wav", 1, ATTN_NORM); +} + +void poison_think () +{ + self.enemy.deathtype="poison"; + T_Damage (self.enemy, self, self.owner, 1 ); + if(self.enemy.flags&FL_CLIENT) + stuffcmd(self.enemy,"bf\n"); + if(self.lifetime .20) + chance = .20; + + if (chance < random()) + return(FALSE); + + centerprint (self,"Your God has saved your mortal body!"); + self.health = self.max_health; + self.cnt_teleport += 1; + Use_TeleportCoin(); + + self.cnt_invincibility += 1; + UseInvincibility (); + self.invincible_time = time + 5; + + self.cnt_tome += 1; + Use_TomeofPower (); + + self.artifact_active(+)ARTFLAG_DIVINE_INTERVENTION; + self.divine_time = time + HX_FRAME_TIME; + sound (self, CHAN_BODY, "paladin/devine.wav", 1, ATTN_NORM); + + return(TRUE); +} + +/* +============ +Killed +============ +*/ +void(entity targ, entity attacker, entity inflictor, float damage, vector dir) Killed = +{ +entity oself; +float was_alive; + oself = self; + self = targ; + + if(!self.flags2&FL_ALIVE) + if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE) + { // doors, triggers, etc + if(self.th_die) + self.th_die(); + self=oself; + return; + } + + was_alive = self.flags2&FL_ALIVE; + if(self.flags2&FL2_EXCALIBUR) + { + WriteTeam (SVC_NODOC,self); + WriteByte (MSG_ALL, SVC_MIDI_NAME); + WriteString (MSG_ALL, "");//stops midi + if(!gameover) + centerprint_all_clients("The Defender of the Crown has been killed!\n",world); + dprint(attacker.netname); + dprint(" killed the defender of the crown\n"); + } + + self.flags2(-)FL_ALIVE|FL2_EXCALIBUR|FL2_HARDFALL; + self.touch = self.th_pain = SUB_Null; + + if (attacker.classname == "player") + { + if ((attacker.playerclass==CLASS_NECROMANCER) && (attacker.level >= 3)) + { + if ((targ.flags & FL_MONSTER) || (targ.flags & FL_CLIENT)) + necromancer_sphere (attacker); + } + else if ((attacker.playerclass==CLASS_CRUSADER) && (attacker.level >= 3)) + { + if ((targ.flags & FL_MONSTER) || (targ.flags & FL_CLIENT)) + crusader_sphere (attacker); + } + } + + if(self.classname=="barrel") + if(inflictor.classname=="balbolt") + self.frags = TRUE; + + //Check for decapitation death + self.movedir='0 0 0'; + if(attacker.beast_time>time) + self.decap=FALSE; + else if((attacker.flags2&FL2_EXCALIBUR&&self.classname=="player")||(attacker.classname=="monster_mezzoman"&&random()<0.3)) + { + self.decap=TRUE; + if(self.health<-20) + self.health=-20; + } + else if(self.model!="models/sheep.mdl"&&self.deathtype!="teledeath"&&self.deathtype!="teledeath2"&&self.deathtype!="teledeath3"&&self.deathtype != "teledeath4") + if + (inflictor.classname=="ax_blade"|| + (inflictor.classname=="player"&& + ( +// (attacker.playerclass==CLASS_ASSASSIN&&attacker.weapon==IT_WEAPON1)|| + (attacker.playerclass==CLASS_PALADIN&&attacker.weapon!=IT_WEAPON3)|| + (attacker.playerclass==CLASS_NECROMANCER&&attacker.weapon==IT_WEAPON1)|| + (attacker.playerclass==CLASS_SUCCUBUS&&attacker.weapon==IT_WEAPON2)|| + (attacker.playerclass==CLASS_DWARF&&attacker.view_ofs_z>=targ.proj_ofs_z) + ) + ) + ) + if(attacker.playerclass==CLASS_DWARF&&attacker.weapon==IT_WEAPON3) + self.decap=2; + else + self.decap=TRUE; + else if(inflictor.classname!="player"&&vlen(inflictor.origin-self.origin+self.view_ofs)<=17&&self.health>=-40&&self.health<-10) + if(random()<0.4) + { + self.movedir=normalize(self.origin+self.view_ofs-inflictor.origin); + self.decap=2; + } + + if(self.skin==GLOBAL_SKIN_STONE||self.frozen>0) + { //Frozen or stoned + if(self.classname!="player") + self.th_die=shatter; + thinktime self : 0; + self.attack_finished=time; + self.pausetime=time; + self.teleport_time=time; + if(self.frozen>0) + self.deathtype="ice shatter"; + else if(self.skin==GLOBAL_SKIN_STONE) + self.deathtype="stone crumble"; + } + + if (self.classname == "player") + { + print_ent1=attacker; + print_ent2=self; + ClientObituary(self, attacker, inflictor); + print_ent1=print_ent2=world; + } + + self.credit_enemy=world; + self.enemy = attacker; + +// bump the monster counter + if (self.flags & FL_MONSTER) + { + MonsterDropStuff(); + killed_monsters = killed_monsters + 1; + WriteByte (MSG_ALL, SVC_KILLEDMONSTER); + monster_death_use(); + pitch_roll_for_slope('0 0 0'); + } + else if(self.th_die==SUB_Null) + if(self.target) + SUB_UseTargets(); + + if(self.classname=="player"&&self.puzzle_inv1!="") + { + self.puzzle_id=self.puzzle_inv1; + DropPuzzlePiece(); + self.puzzle_inv1=self.puzzle_id=""; + } + + self.th_stand=self.th_walk=self.th_run=self.th_pain=self.oldthink=self.think=self.th_melee=self.th_missile=SUB_Null; + + if(pointcontents(self.origin+self.view_ofs)==CONTENT_WATER) + DeathBubbles(20); + +// if(attacker.classname=="rider_death") +// spawn_ghost(attacker); + + self.beast_time=0; + if(self.classname=="player_sheep") + self.enemy=attacker; + + if(oself!=targ) + { + if(self.classname=="player") + PlayerDie(damage, dir); + else if (self.th_die) + self.th_die (); + + self = oself; + } + else + { + if(self.classname=="player") + { + PlayerDie(damage, dir); + //self.think=PlayerDie; + } + else if (self.th_die) + self.think=self.th_die; + thinktime self : 0; + } + if (self.health < -99) + self.health = -99; // don't let sbar look bad if a player +}; + + +void monster_pissed (entity attacker) +{ + if(attacker.siege_team==self.siege_team) + return; + + if(self.controller.classname=="player") + {//Summoned/controlled monsters + if(coop) + if(attacker.classname=="player") + return; + + if(deathmatch&&teamplay) + if((attacker.team==self.controller.team)||(attacker.siege_team==self.controller.siege_team)) + return; + } + + if (self.enemy.classname == "player") + self.oldenemy = self.enemy; + self.enemy = attacker; + self.goalentity = self.enemy; + + if (self.th_walk) + FoundTarget (); +} + +float armor_inv(entity victim) +{ + float armor_cnt; + + armor_cnt =0; + + if (victim.armor_amulet) + armor_cnt += 1; + + if (victim.armor_bracer) + armor_cnt += 1; + + if (victim.armor_breastplate) + armor_cnt += 1; + + if (victim.armor_helmet) + armor_cnt += 1; + + return(armor_cnt); +} + +float armor_calc(entity targ,float damage) +{ + float total_armor_protection; + float armor_cnt; + float armor_damage; + float perpiece; + float curr_damage,armor_damage; + + total_armor_protection = 0; + + if (targ.armor_amulet) + total_armor_protection += ClassArmorProtection[targ.playerclass - 1]; + + if (targ.armor_bracer) + total_armor_protection += ClassArmorProtection[targ.playerclass - 1 + 1]; + + if (targ.armor_breastplate) + total_armor_protection += ClassArmorProtection[targ.playerclass - 1 + 2]; + + if (targ.armor_helmet) + total_armor_protection += ClassArmorProtection[targ.playerclass - 1 + 3]; + + total_armor_protection += targ.level * .001; + + armor_cnt = armor_inv(targ); + + if (armor_cnt) // There is armor + { + armor_damage = total_armor_protection * damage; + + // Damage is greater than all the armor + if (armor_damage > (targ.armor_amulet + targ.armor_bracer + + targ.armor_breastplate + targ.armor_helmet)) + { + targ.armor_amulet = 0; + targ.armor_bracer = 0; + targ.armor_breastplate = 0; + targ.armor_helmet = 0; + } + else // Damage the armor + { + curr_damage = armor_damage; + // FIXME: Commented out the loop for E3 because of a runaway loop message + // while (curr_damage>0) + // { + armor_cnt = armor_inv(targ); + + perpiece = curr_damage / armor_cnt; + + if ((targ.armor_amulet) && (curr_damage)) + { + targ.armor_amulet -= perpiece; + curr_damage -= perpiece; + if (targ.armor_amulet < 0) + { + curr_damage -= targ.armor_amulet; + targ.armor_amulet = 0; + } + + if (targ.armor_amulet < 1) + targ.armor_amulet = 0; + } + + if ((targ.armor_bracer) && (curr_damage)) + { + targ.armor_bracer -= perpiece; + curr_damage -= perpiece; + if (targ.armor_bracer < 0) + { + curr_damage -= targ.armor_bracer; + targ.armor_bracer = 0; + } + + if (targ.armor_bracer < 1) + targ.armor_bracer = 0; + } + + if ((targ.armor_breastplate) && (curr_damage)) + { + targ.armor_breastplate -= perpiece; + curr_damage -= perpiece; + if (targ.armor_breastplate < 0) + { + curr_damage -= targ.armor_breastplate; + targ.armor_breastplate = 0; + } + + if (targ.armor_breastplate < 1) + targ.armor_breastplate = 0; + } + + if ((targ.armor_helmet) && (curr_damage)) + { + targ.armor_helmet -= perpiece; + curr_damage -= perpiece; + if (targ.armor_helmet < 0) + { + curr_damage -= targ.armor_helmet; + targ.armor_helmet = 0; + } + + if (targ.armor_helmet < 1) + targ.armor_helmet = 0; + } + + // } + } + } + else + armor_damage =0; + + return(armor_damage); +} + +void MeleeSpark (entity ent1,entity ent2) +{ +vector p1,p2; +float r; + p1=ent1.origin+ent2.proj_ofs; + p2=ent2.origin+ent2.proj_ofs; + p1_x=(p1_x+p2_x)*0.5; + p1_y=(p1_y+p2_y)*0.5; + p1_z=(p1_z+p2_z)*0.5; + + r=random(); + if(r<0.33) + { + ent1.effects(+)EF_MUZZLEFLASH; + sound (ent1, CHAN_AUTO, "weapons/met2met.wav", 1, ATTN_NORM); + } + else if(r<0.66) + { + ent2.effects(+)EF_MUZZLEFLASH; + sound(ent2,CHAN_AUTO,"weapons/hitwall.wav",0.5,ATTN_NORM); + } + else + { + ent1.effects(+)EF_MUZZLEFLASH; + sound(ent1,CHAN_AUTO,"paladin/axric1.wav",0.75,ATTN_NORM); + } + + r=random(); + if(r<0.33) + starteffect(CE_BLUESPARK,p1); + else if(r<0.66) + starteffect(CE_REDSPARK,p1); + else + starteffect(CE_YELLOWSPARK,p1); +} + +float using_melee (entity who) +{ + switch(who.playerclass) + { + case CLASS_DWARF: + return TRUE; + break; + case CLASS_PALADIN: + if(who.weapon!=IT_WEAPON3) + return TRUE; + return FALSE; + break; + case CLASS_CRUSADER: + case CLASS_NECROMANCER: + case CLASS_ASSASSIN: + if(who.weapon==IT_WEAPON1) + return TRUE; + return FALSE; + break; + case CLASS_SUCCUBUS: + if(who.weapon==IT_WEAPON2) + return TRUE; + return FALSE; + break; + default: + return FALSE; + break; + } +} + +/* +============ +T_Damage + +The damage is coming from inflictor, but get mad at attacker +This should be the only function that ever reduces health. +============ +*/ +void(entity targ, entity inflictor, entity attacker, float damage) T_Damage= +{ +vector dir; +entity oldself; +float save; +float total_damage,do_mod;//,hurt_exp_award; +float armor_damage;//,alt_award; +entity holdent;//,lastleader,newking; +float wrath; + + if (!targ.takedamage) + return; + + if(attacker.flags2&FL2_PARRIED) + { + attacker.flags2(-)FL2_PARRIED; + return; + } + + if(targ.invincible_time>time) + { + sound(targ,CHAN_ITEM,"misc/pulse.wav",1,ATTN_NORM); + return; + } + + if(targ!=attacker) + if (targ.deathtype != "teledeath"&&targ.deathtype != "teledeath2"&&targ.deathtype != "teledeath3"&&targ.deathtype != "teledeath4") + { + if(coop&&teamplay&&attacker.classname=="player"&&targ.classname=="player") + return; + + if(teamplay) + if(attacker.classname=="player"&&targ.classname=="player") + if((attacker.team==targ.team&&dmMode!=DM_SIEGE)||(attacker.siege_team==targ.siege_team&&dmMode==DM_SIEGE)) + return;//can't hurt pals + } + + if (targ.flags & FL_GODMODE) + return; + + if(targ.classname=="monster_mezzoman") + { + if(inflictor.flags2&FL_NODAMAGE) + { + inflictor.flags2(-)FL_NODAMAGE; + if(random()<0.3) + CreateSpark (inflictor.origin); + return; + } + + if(targ.movechain.classname=="mezzo reflect") + if(infront_of_ent(inflictor,targ)) + { + sound(targ,CHAN_AUTO,"mezzo/slam.wav",1,ATTN_NORM); + makevectors(targ.angles); + if(random()<0.1) + CreateSpark(targ.origin+targ.view_ofs+v_forward*12); + else if(random()<0.7) + particle4(targ.origin+targ.view_ofs+v_forward*12,random(5,15),256 + (8 * 15),PARTICLETYPE_FASTGRAV,2 * damage); + return; + } + } + + // Nothing but melee weapons hurt the snake +// if ((targ.classname == "monster_snake") && +// ((!inflictor.classname == "player") || (!attacker.classname == "player"))) +// return; + + if(targ.health<=0) + { + targ.health=targ.health-damage;//Keep taking damage while dying, if enough, may gib in mid-death + return; + } + + + if(attacker==inflictor)//melee + if(targ.last_attack+0.75>=time) + if(using_melee(attacker)) + if(using_melee(targ)) + if(random()<0.3) + if(fov(targ,attacker,20)) + if(fov(attacker,targ,20)) + { + MeleeSpark(attacker,targ); + targ.flags2(+)FL2_PARRIED; + return; + } + +//Credit for certain types of kills, like freezing or pushing off ledges into lava, etc. +/* + if(targ.classname=="player") + if(targ.credit_enemy!=world&&targ.credit_enemy!=attacker) + if((attacker!=world||pointcontents(targ.origin)!=CONTENT_LAVA)&&(!targ.artifact_active&ARTFLAG_FROZEN)) + targ.credit_enemy=world;//was hit by someone else or not taking lava damage, and not frozen, so clear credit_enemy +*/ +//Damage modifiers +// used by buttons and triggers to set activator for target firing + + + if(damageScale > 0) + { + damage *= damageScale; + } + + if (meleeDamScale > 0) + { + if (targ.weapon==IT_WEAPON1) + { + damage *= meleeDamScale; + } + } + + if((dmMode == DM_CAPTURE_THE_TOKEN)&&(attacker.gameFlags & GF_HAS_TOKEN)) + { + damage *= 2.0; + } + else if((dmMode == DM_CAPTURE_THE_TOKEN)&&(targ.gameFlags & GF_HAS_TOKEN)) + { + damage *= .5; + } + + if(targ.flags2&FL2_EXCALIBUR) + damage*=random(.2)+ 0.2;//20% - 40% damage to excalibur holder + +/* if(attacker.classname=="player"&&deathmatch) + { // adjust damage based on the level of the player + damage *= (1.0 + (attacker.level - 1)*0.14); + }*/ + + damage_attacker = attacker; + + if(attacker.flags&FL_CLIENT&&attacker==inflictor) + {//Damage mod for strength using melee weaps + if( + (attacker.weapon==IT_WEAPON1&&attacker.playerclass!=CLASS_SUCCUBUS)|| + (attacker.weapon==IT_WEAPON2&&(attacker.playerclass==CLASS_PALADIN||attacker.playerclass==CLASS_DWARF)) + ) + { + if(attacker.playerclass==CLASS_CRUSADER) + { + if(!attacker.artifact_active&ART_TOMEOFPOWER) + do_mod=TRUE; + } + else + do_mod=TRUE; + } + if(do_mod) + { + do_mod = attacker.strength - 11; + damage+=damage*do_mod/30;//from .84 - 1.23 + } + } + + if(targ.flags&FL_MONSTER&&inflictor.flags2&FL2_ADJUST_MON_DAM) + damage*=2;//Special- more damage against monsters + + if (attacker.super_damage) + damage += attacker.super_damage * damage; + + // Calculating Damage to a player + if (targ.classname == "player"&&!targ.flags2&FL2_HARDFALL) + { // How much armor does he have + if(inflictor.classname=="balbolt"&&targ.playerclass!=CLASS_DWARF) + armor_damage = 0; + else + armor_damage = armor_calc(targ,damage); + + // What hits player + total_damage = damage - armor_damage; + } + else + total_damage = damage; + +// add to the damage total for clients, which will be sent as a single +// message at the end of the frame +// FIXME: remove after combining shotgun blasts? + if (targ.flags & FL_CLIENT) + { + targ.dmg_take = targ.dmg_take + total_damage; + targ.dmg_save = targ.dmg_save + save; + targ.dmg_inflictor = inflictor; + } + +// figure momentum add + if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) ) + { + dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; + dir = normalize(dir); + targ.velocity = targ.velocity + dir*damage*8; + } + +// check for godmode or invincibility +// do the damage + targ.health = targ.health - total_damage; + + if(targ.health>=0&&targ.health<1.0000)//No more Zombie mode!!! (Sorry!) + targ.health=-0.1; + + if (targ.health <=0 && targ.classname == "player" && targ.cnt_sh_boost) + { + if (deathmatch || skill == 0) // Only in deatmatch or easy mode + { + holdent = self; + self = targ; + use_super_healthboost(); + centerprint(self,"Saved by the Mystic Urn!\n"); + stuffcmd(self,"bf\n"); + sound (self, CHAN_AUTO, "misc/comm.wav", 1, ATTN_NORM); + self.deathtype=""; + self = holdent; + return; + } + } + + if(self.deathtype!="smitten")//nothing stops the REAL GOD (server) + { + // Check to see if divine intervention took place + if(attacker.playerclass==CLASS_CRUSADER&&attacker.weapon==IT_WEAPON8)//divine intervention + wrath=TRUE; + else + wrath=FALSE; + + if(!wrath||(wrath&&random()<0.3&&targ==attacker))//30 % chance to allow possibility of saving caster from wrath, no others may be spared + if ((targ.health <= 0) && (targ.classname == "player") && (targ.playerclass == CLASS_CRUSADER)) + { + holdent = self; + self = targ; + if (Pal_DivineIntervention()) + { + self.deathtype=""; + self = holdent; + return; + } + self = holdent; + } + } + + + if(targ.classname=="monster_imp_lord") + if(targ.controller) + T_Damage(targ.controller,attacker,attacker,total_damage/3.33); + + if (targ.health <= 0) + { + if(inflictor.classname=="minigrenade"&&targ.health>-40) + targ.health=-40+random(-1,-20);//Ensure gib deathtype + + if(attacker.controller.classname=="player") + {//Proper frag credit to controller of summoned stuff + inflictor=attacker; + attacker=attacker.controller; + } + targ.th_pain=SUB_Null; //Should prevents interruption of death sequence + Killed (targ, attacker,inflictor, total_damage, targ.origin - attacker.origin); + return; + } + +// react to the damage + oldself = self; + self = targ; + +// barrels need sliding information + if (self.classname == "barrel") + { + self.enemy = inflictor; + self.count = damage; + } + else if (self.classname == "catapult") + { + self.enemy = inflictor; + if(attacker.siege_team==ST_ATTACKER) + self.health+=total_damage;//can't take damage from attacker hits + } + else if(self.classname=="player") + self.enemy = attacker; + + if ( (self.flags & FL_MONSTER) && attacker != world && !(attacker.flags & FL_NOTARGET)&&attacker!=self.controller&&(attacker.controller!=self.controller||attacker.controller==world)) + { // Monster's shouldn't attack each other (kin don't shoot kin) + if (self != attacker && attacker != self.enemy&&(self.enemy.classname!="player"||attacker.classname=="player"||attacker.controller.classname=="player"))// && attacker.flags & FL_CLIENT) + { + if (self.classname != attacker.classname||random(100)<=5) //5% chance they'll turn on selves + { + if((self.model=="models/spider.mdl"||self.model=="models/scorpion.mdl")&&attacker.model==self.model) + { + if(random()<0.3) + monster_pissed(attacker); + } + else + monster_pissed(attacker); + } + } + } + + if((self.classname=="door"||self.classname=="door_rotating")&&self.takedamage) + { + if(!self.pain_target) + self.pain_target="rippler"; + breakable_hurt_use(attacker,total_damage); + } + + if (self.th_pain) + { + if(self.classname=="player"&&self.model!="models/sheep.mdl") + player_pain(attacker,total_damage); + else + self.th_pain (attacker, total_damage); + // nightmare mode monsters don't go into pain frames often + if (skill == 3) + self.pain_finished = time + 5; + } + + self = oldself; +}; + +/* +============ +T_RadiusDamage +============ +*/ +//void(entity loser)SpawnFlameOn; +void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage = +{ +float points,inertia,radius; +entity head; +vector inflictor_org, org; + +//FIXME: If too many radius damage effects go off at the same time, it crashes in a loop +// This usually occurs when object whose death is radius damage destoy +// other objects with a radius damage death (namely: exploding barrels) + + if(inflictor.flags&FL_CLIENT)//more damage up top + inflictor_org = inflictor.origin+inflictor.view_ofs; + else + inflictor_org = (inflictor.absmin+inflictor.absmax)*0.5; + if(inflictor.classname=="circfire") + radius=150; + else if(inflictor.classname=="poison grenade") + radius=200;//FIXME- greater distance above... + else + radius=damage+40; + + if (inflictor.classname == "pincer" && radius > 200) + { + radius = 200; + } + + head = findradius(inflictor_org, radius); + + if(inflictor.classname=="fireballblast") + damage+=attacker.level*33; + + while (head) + { + if (head != ignore&&head!=inflictor)// && head!=inflictor.owner) + { + if (head.takedamage) + { + org = (head.absmax + head.absmin)*0.5; + if(inflictor.classname=="poison grenade") + { + if(head.flags2&FL_ALIVE&&head.thingtype==THINGTYPE_FLESH) + points=0; + else + points=damage; + } + else + points = 0.5*vlen (inflictor_org - org); + if (points < 0) + points = 0; + points = damage - points; + if (head == attacker) + if(attacker.classname=="monster_eidolon")//Necromancer takes no radius damage from his own magic + points = 0; + else if(inflictor.model=="models/assgren.mdl")//Some more resistance to the Assassin's own Big One + points*=0.5; + else + points*=0.5; + + //following stops multiple grenades from blowing each other up + if(head.owner==inflictor.owner&& + head.classname==inflictor.classname&& + (head.classname=="stickmine"||head.classname=="tripwire"||head.classname=="proximity")) + points=0; + if((inflictor.classname=="snowball"||inflictor.classname=="blizzard")&&head.frozen>0) + points=0; + if (points > 0) + { + if (CanDamage (head, inflictor)||inflictor.classname=="fireballblast") + { + if(other.movetype!=MOVETYPE_PUSH) + { + if (head.mass<=10) + inertia = 1; + else if(head.mass<=100) + inertia = head.mass/10; + else + inertia = head.mass; + head.velocity=head.velocity+normalize(org-inflictor_org)*(points*10/inertia); + if(head.velocity_z<30&&head.flags&FL_ONGROUND) + head.velocity_z=30; + head.flags(-)FL_ONGROUND; + } + + if(inflictor.classname=="poison grenade") + { + if(!head.flags2&FL2_POISONED) + {//Poison them + if(head.flags&FL_CLIENT&&(coop||teamplay==1)) + { + if(head.team!=attacker.team&&!coop) + { + centerprint(head,"You have been poisoned!\n"); + spawn_poison(head,attacker,random(10,20)); + } + } + else + spawn_poison(head,attacker,random(10,20)); + } + } + else if(inflictor.netname=="obj_barrel_gfire") + { + //if(points>10) + if(flammable(head)) + { + points/=2;//not so much radius damage + if(!head.flags2&FL2_ONFIRE) + spawn_burner(head,TRUE); + else + head.fire_damage += 2;//burn more! + } + else + points=3; + } + else if(inflictor.classname=="fireballblast") + { + if(points>10||points<5) + points=random(5,10); + + if(head.health<=points) + points=1000; + T_Damage (head, inflictor, attacker, points); + } + else + T_Damage (head, inflictor, attacker, points); + } + } + } + } + head = head.chain; + } +}; + +/* +============ +T_RadiusDamageWater +============ +*/ + +void(entity inflictor, entity attacker, float dam, entity ignore) T_RadiusDamageWater = +{ +float points; +entity head; +vector org; + + head = findradius(inflictor.origin, dam); + + while (head) + { + if (head != ignore) + { + if (head.takedamage) + { + if (pointcontents(head.origin) == CONTENT_WATER || pointcontents(head.origin) == CONTENT_SLIME) // visible(inflictor)? + { + if (head.classname == "player" && head != attacker) + head.enemy = attacker; + org = head.origin + (head.mins + head.maxs)*0.5; + points = 0.25 * vlen (inflictor.origin - org); + if (points <= 64) + points = 1; + points = dam/points; + if (points < 1||(self.classname=="mjolnir"&&head==self.controller)||head.classname=="monster_hydra") + points = 0; + if (points > 0) + { + head.deathtype="zap"; + spawnshockball((head.absmax+head.absmin)*0.5); + T_Damage (head, inflictor, attacker, points); +//Bubbles if dead? + } + } + } + } + head = head.chain; + } +}; + +/* +============ +T_BeamDamage +============ +*/ +/* +void(entity attacker, float damage) T_BeamDamage = +{ + local float points; + local entity head; + + head = findradius(attacker.origin, damage+40); + + while (head) + { + if (head.takedamage) + { + points = 0.5*vlen (attacker.origin - head.origin); + if (points < 0) + points = 0; + points = damage - points; + if (head == attacker) + points = points * 0.5; + if (points > 0) + { + if (CanDamage (head, attacker)) + T_Damage (head, attacker, attacker, points); + } + } + head = head.chain; + } +}; +*/ +/* +============ +T_RadiusManaDamage +============ +*/ +/* +void(entity inflictor, entity attacker, float manadamage, entity ignore) T_RadiusManaDamage = +{ + local float points; + local entity head; + local vector org; + + head = findradius(inflictor.origin, manadamage); + + while (head) + { + if (head != ignore) + { + if ((head.takedamage) && (head.classname=="player")) + { + org = head.origin + (head.mins + head.maxs)*0.5; + points = 0.5 * vlen (inflictor.origin - org); + if (points < 0) + points = 0; + points = manadamage - points; + if (head == attacker) + points = points * 0.5; + if (points > 0) + { + if (CanDamage (head, inflictor)) + { + head.bluemana = head.bluemana - points; + if (head.bluemana<0) + head.bluemana=0; + head.greenmana = head.greenmana - points; + if (head.greenmana<0) + head.greenmana=0; + } + } + } + } + head = head.chain; + } +}; +*/ + diff --git a/defs.hc b/defs.hc new file mode 100644 index 0000000..669d0b1 --- /dev/null +++ b/defs.hc @@ -0,0 +1,5 @@ +/* + * $Header: /HexenWorld/Siege/Defs.hc 3 5/25/98 1:38p Mgummelt $ + */ + +// !!! Not used !!! diff --git a/demon.hc b/demon.hc new file mode 100644 index 0000000..041ee80 --- /dev/null +++ b/demon.hc @@ -0,0 +1,368 @@ +/* + * $Header: /HexenWorld/Siege/Demon.hc 3 5/25/98 1:38p Mgummelt $ + */ +/* +============================================================================== + +DEMON + +============================================================================== +*/ + +$cd id1/models/demon3 +$scale 0.8 +$origin 0 0 24 +$base base +$skin base + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 + +$frame run1 run2 run3 run4 run5 run6 + +$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9 leap10 +$frame leap11 leap12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 + +$frame attacka1 attacka2 attacka3 attacka4 attacka5 attacka6 attacka7 attacka8 +$frame attacka9 attacka10 attacka11 attacka12 attacka13 attacka14 attacka15 + +//============================================================================ + +void() Demon_JumpTouch; + +void() demon1_stand1 =[ $stand1, demon1_stand2 ] {ai_stand();}; +void() demon1_stand2 =[ $stand2, demon1_stand3 ] {ai_stand();}; +void() demon1_stand3 =[ $stand3, demon1_stand4 ] {ai_stand();}; +void() demon1_stand4 =[ $stand4, demon1_stand5 ] {ai_stand();}; +void() demon1_stand5 =[ $stand5, demon1_stand6 ] {ai_stand();}; +void() demon1_stand6 =[ $stand6, demon1_stand7 ] {ai_stand();}; +void() demon1_stand7 =[ $stand7, demon1_stand8 ] {ai_stand();}; +void() demon1_stand8 =[ $stand8, demon1_stand9 ] {ai_stand();}; +void() demon1_stand9 =[ $stand9, demon1_stand10 ] {ai_stand();}; +void() demon1_stand10 =[ $stand10, demon1_stand11 ] {ai_stand();}; +void() demon1_stand11 =[ $stand11, demon1_stand12 ] {ai_stand();}; +void() demon1_stand12 =[ $stand12, demon1_stand13 ] {ai_stand();}; +void() demon1_stand13 =[ $stand13, demon1_stand1 ] {ai_stand();}; + +void() demon1_walk1 =[ $walk1, demon1_walk2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE); +ai_walk(8); +}; +void() demon1_walk2 =[ $walk2, demon1_walk3 ] {ai_walk(6);}; +void() demon1_walk3 =[ $walk3, demon1_walk4 ] {ai_walk(6);}; +void() demon1_walk4 =[ $walk4, demon1_walk5 ] {ai_walk(7);}; +void() demon1_walk5 =[ $walk5, demon1_walk6 ] {ai_walk(4);}; +void() demon1_walk6 =[ $walk6, demon1_walk7 ] {ai_walk(6);}; +void() demon1_walk7 =[ $walk7, demon1_walk8 ] {ai_walk(10);}; +void() demon1_walk8 =[ $walk8, demon1_walk1 ] {ai_walk(10);}; + +void() demon1_run1 =[ $run1, demon1_run2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE); +ai_run(20);}; +void() demon1_run2 =[ $run2, demon1_run3 ] {ai_run(15);}; +void() demon1_run3 =[ $run3, demon1_run4 ] {ai_run(36);}; +void() demon1_run4 =[ $run4, demon1_run5 ] {ai_run(20);}; +void() demon1_run5 =[ $run5, demon1_run6 ] {ai_run(15);}; +void() demon1_run6 =[ $run6, demon1_run1 ] {ai_run(36);}; + +void() demon1_jump1 =[ $leap1, demon1_jump2 ] {ai_face();}; +void() demon1_jump2 =[ $leap2, demon1_jump3 ] {ai_face();}; +void() demon1_jump3 =[ $leap3, demon1_jump4 ] {ai_face();}; +void() demon1_jump4 =[ $leap4, demon1_jump5 ] +{ + ai_face(); + + self.touch = Demon_JumpTouch; + makevectors (self.angles); + self.origin_z = self.origin_z + 1; + self.velocity = v_forward * 600 + '0 0 250'; + if (self.flags & FL_ONGROUND) + self.flags = self.flags - FL_ONGROUND; +}; +void() demon1_jump5 =[ $leap5, demon1_jump6 ] {}; +void() demon1_jump6 =[ $leap6, demon1_jump7 ] {}; +void() demon1_jump7 =[ $leap7, demon1_jump8 ] {}; +void() demon1_jump8 =[ $leap8, demon1_jump9 ] {}; +void() demon1_jump9 =[ $leap9, demon1_jump10 ] {}; +void() demon1_jump10 =[ $leap10, demon1_jump1 ] { +self.nextthink = time + 3; +// if three seconds pass, assume demon is stuck and jump again +}; + +void() demon1_jump11 =[ $leap11, demon1_jump12 ] {}; +void() demon1_jump12 =[ $leap12, demon1_run1 ] {}; + + +void() demon1_atta1 =[ $attacka1, demon1_atta2 ] {ai_charge(4);}; +void() demon1_atta2 =[ $attacka2, demon1_atta3 ] {ai_charge(0);}; +void() demon1_atta3 =[ $attacka3, demon1_atta4 ] {ai_charge(0);}; +void() demon1_atta4 =[ $attacka4, demon1_atta5 ] {ai_charge(1);}; +void() demon1_atta5 =[ $attacka5, demon1_atta6 ] {ai_charge(2); Demon_Melee(200);}; +void() demon1_atta6 =[ $attacka6, demon1_atta7 ] {ai_charge(1);}; +void() demon1_atta7 =[ $attacka7, demon1_atta8 ] {ai_charge(6);}; +void() demon1_atta8 =[ $attacka8, demon1_atta9 ] {ai_charge(8);}; +void() demon1_atta9 =[ $attacka9, demon1_atta10] {ai_charge(4);}; +void() demon1_atta10 =[ $attacka10, demon1_atta11] {ai_charge(2);}; +void() demon1_atta11 =[ $attacka11, demon1_atta12] {Demon_Melee(-200);}; +void() demon1_atta12 =[ $attacka12, demon1_atta13] {ai_charge(5);}; +void() demon1_atta13 =[ $attacka13, demon1_atta14] {ai_charge(8);}; +void() demon1_atta14 =[ $attacka14, demon1_atta15] {ai_charge(4);}; +void() demon1_atta15 =[ $attacka15, demon1_run1] {ai_charge(4);}; + +void() demon1_pain1 =[ $pain1, demon1_pain2 ] {}; +void() demon1_pain2 =[ $pain2, demon1_pain3 ] {}; +void() demon1_pain3 =[ $pain3, demon1_pain4 ] {}; +void() demon1_pain4 =[ $pain4, demon1_pain5 ] {}; +void() demon1_pain5 =[ $pain5, demon1_pain6 ] {}; +void() demon1_pain6 =[ $pain6, demon1_run1 ] {}; + +void(entity attacker, float damage) demon1_pain = +{ + if (self.touch == Demon_JumpTouch) + return; + + if (self.pain_finished > time) + return; + + self.pain_finished = time + 1; + sound (self, CHAN_VOICE, "demon/dpain1.wav", 1, ATTN_NORM); + + if (random()*200 > damage) + return; // didn't flinch + + demon1_pain1 (); +}; + +void() demon1_die1 =[ $death1, demon1_die2 ] { +sound (self, CHAN_VOICE, "demon/ddeath.wav", 1, ATTN_NORM);}; +void() demon1_die2 =[ $death2, demon1_die3 ] {}; +void() demon1_die3 =[ $death3, demon1_die4 ] {}; +void() demon1_die4 =[ $death4, demon1_die5 ] {}; +void() demon1_die5 =[ $death5, demon1_die6 ] {}; +void() demon1_die6 =[ $death6, demon1_die7 ] +{self.solid = SOLID_NOT;}; +void() demon1_die7 =[ $death7, demon1_die8 ] {}; +void() demon1_die8 =[ $death8, demon1_die9 ] {}; +void() demon1_die9 =[ $death9, demon1_die9 ] {}; + +void() demon_die = +{ +// check for gib + if (self.health < -80) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("progs/h_demon.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + return; + } + +// regular death + demon1_die1 (); +}; + + +void() Demon_MeleeAttack = +{ + demon1_atta1 (); +}; + + +/*QUAK-ED monster_demon1 (1 0 0) (-32 -32 -24) (32 32 64) Ambush +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() monster_demon1 = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/demon.mdl"); + precache_model ("progs/h_demon.mdl"); + + precache_sound ("demon/ddeath.wav"); + precache_sound ("weapons/slash.wav"); + precache_sound ("demon/djump.wav"); + precache_sound ("demon/dpain1.wav"); + precache_sound ("demon/idle1.wav"); + precache_sound ("demon/sight2.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/demon.mdl"); + + setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); + self.health = 300; + + self.th_stand = demon1_stand1; + self.th_walk = demon1_walk1; + self.th_run = demon1_run1; + self.th_die = demon_die; + self.th_melee = Demon_MeleeAttack; // one of two attacks + self.th_missile = demon1_jump1; // jump attack + self.th_pain = demon1_pain; + + walkmonster_start(); +}; + + +/* +============================================================================== + +DEMON + +============================================================================== +*/ + +/* +============== +CheckDemonMelee + +Returns TRUE if a melee attack would hit right now +============== +*/ +float() CheckDemonMelee = +{ + if (enemy_range == RANGE_MELEE) + { // FIXME: check canreach + self.attack_state = AS_MELEE; + return TRUE; + } + return FALSE; +}; + +/* +============== +CheckDemonJump + +============== +*/ +float() CheckDemonJump = +{ + local vector dist; + local float d; + + if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z + + 0.75 * self.enemy.size_z) + return FALSE; + + if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z + + 0.25 * self.enemy.size_z) + return FALSE; + + dist = self.enemy.origin - self.origin; + dist_z = 0; + + d = vlen(dist); + + if (d < 100) + return FALSE; + + if (d > 200) + { + if (random() < 0.9) + return FALSE; + } + + return TRUE; +}; + +float() DemonCheckAttack = +{ + local vector vec; + +// if close enough for slashing, go for it + if (CheckDemonMelee ()) + { + self.attack_state = AS_MELEE; + return TRUE; + } + + if (CheckDemonJump ()) + { + self.attack_state = AS_MISSILE; + sound (self, CHAN_VOICE, "demon/djump.wav", 1, ATTN_NORM); + return TRUE; + } + + return FALSE; +}; + + +//=========================================================================== + +void(float side) Demon_Melee = +{ + local float ldmg; + local vector delta; + + ai_face (); + walkmove (self.ideal_yaw, 12); // allow a little closing + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 100) + return; + if (!CanDamage (self.enemy, self)) + return; + + sound (self, CHAN_WEAPON, "weapons/slash.wav", 1, ATTN_NORM); + ldmg = 10 + 5*random(); + T_Damage (self.enemy, self, self, ldmg); + + makevectors (self.angles); + SpawnMeatSpray (self.origin + v_forward*16, side * v_right); +}; + + +void() Demon_JumpTouch = +{ + local float ldmg; + + if (self.health <= 0) + return; + + if (other.takedamage) + { + if ( vlen(self.velocity) > 400 ) + { + ldmg = 40 + 10*random(); + T_Damage (other, self, self, ldmg); + } + } + + if (!checkbottom(self)) + { + if (self.flags & FL_ONGROUND) + { // jump randomly to not get hung up +//dprint ("popjump\n"); + self.touch = SUB_Null; + self.think = demon1_jump1; + self.nextthink = time + 0.1; + +// self.velocity_x = (random() - 0.5) * 600; +// self.velocity_y = (random() - 0.5) * 600; +// self.velocity_z = 200; +// self.flags = self.flags - FL_ONGROUND; + } + return; // not on ground yet + } + + self.touch = SUB_Null; + self.think = demon1_jump11; + self.nextthink = time + 0.1; +}; + diff --git a/dmlevels.hc b/dmlevels.hc new file mode 100644 index 0000000..02ec2fe --- /dev/null +++ b/dmlevels.hc @@ -0,0 +1,129 @@ +/*=========================== + +Level listings for DM- seperate .hc file to make it easy to find. +Change the order to whatever you want and recompile the progs.dat. + +MG +=============================*/ +void FindDMLevel(void) +{ + serverflags (+) SFL_NEW_UNIT; + + nextmap = string_null; + + if(dmMode == DM_SIEGE) + {//FIXME: Check a text file for the next map, else use Siege11? + nextmap = "siege"; + } + else if (cvar("registered") != 0 || cvar("oem") != 0) + {//registered + if (mapname == "demo1") + nextmap = "demo2"; + else if (mapname == "demo2") + nextmap = "demo3"; + else if (mapname == "demo3") + nextmap = "village1"; + else if (mapname == "village1") + nextmap = "village2"; + else if (mapname == "village2") + nextmap = "village3"; + else if (mapname == "village3") + nextmap = "village4"; + else if (mapname == "village4") + nextmap = "village5"; + else if (mapname == "village5") + nextmap = "rider1a"; + else if (mapname == "rider1a") + nextmap = "demo1"; + + else if (mapname == "meso1") + nextmap = "meso2"; + else if (mapname == "meso2") + nextmap = "meso3"; + else if (mapname == "meso3") + nextmap = "meso4"; + else if (mapname == "meso4") + nextmap = "meso5"; + else if (mapname == "meso5") + nextmap = "meso6"; + else if (mapname == "meso6") + nextmap = "meso8"; + else if (mapname == "meso8") + nextmap = "meso9"; + else if (mapname == "meso9") + nextmap = "meso1"; + + else if (mapname == "egypt1") + nextmap = "egypt2"; + else if (mapname == "egypt2") + nextmap = "egypt3"; + else if (mapname == "egypt3") + nextmap = "egypt4"; + else if (mapname == "egypt4") + nextmap = "egypt5"; + else if (mapname == "egypt5") + nextmap = "egypt6"; + else if (mapname == "egypt6") + nextmap = "egypt7"; + else if (mapname == "egypt7") + nextmap = "rider2c"; + else if (mapname == "rider2c") + nextmap = "egypt1"; + + else if (mapname == "romeric1") + nextmap = "romeric2"; + else if (mapname == "romeric2") + nextmap = "romeric3"; + else if (mapname == "romeric3") + nextmap = "romeric4"; + else if (mapname == "romeric4") + nextmap = "romeric5"; + else if (mapname == "romeric5") + nextmap = "romeric6"; + else if (mapname == "romeric6") + nextmap = "romeric7"; + else if (mapname == "romeric7") + nextmap = "romeric1"; + + else if (mapname == "cath") + nextmap = "tower"; + else if (mapname == "tower") + nextmap = "castle4"; + else if (mapname == "castle4") + nextmap = "castle5"; + else if (mapname == "castle5") + nextmap = "eidolon"; + else if (mapname == "eidolon") + nextmap = "cath"; + + else if (mapname == "ravdm1") + nextmap = "ravdm2"; + else if (mapname == "ravdm2") + nextmap = "ravdm3"; + else if (mapname == "ravdm3") + nextmap = "ravdm4"; + else if (mapname == "ravdm4") + nextmap = "ravdm5"; + else if (mapname == "ravdm5") + nextmap = "hwdm1"; + else if (mapname == "hwdm1") + nextmap = "hwdm2"; + else if (mapname == "hwdm2") + nextmap = "hwdm3"; + else if (mapname == "hwdm3") + nextmap = "hwdm4"; + else if (mapname == "hwdm4") + nextmap = "hwdm5"; + else if (mapname == "hwdm5") + nextmap = "ravdm1"; + } + else + {//demo + if (mapname == "demo1") + nextmap = "demo2"; + else if (mapname == "demo2") + nextmap = "ravdm1"; + else if (mapname == "ravdm1") + nextmap = "demo1"; + } +} diff --git a/dog.hc b/dog.hc new file mode 100644 index 0000000..c56156a --- /dev/null +++ b/dog.hc @@ -0,0 +1,369 @@ +/* + * $Header: /HexenWorld/Siege/Dog.hc 3 5/25/98 1:38p Mgummelt $ + */ +/* +============================================================================== + +DOG + +============================================================================== +*/ +$cd id1/models/dog +$origin 0 0 24 +$base base +$skin skin + +$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 + +$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8 +$frame deathb9 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 painb10 +$frame painb11 painb12 painb13 painb14 painb15 painb16 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12 + +$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9 + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 + + +void() dog_leap1; +void() dog_run1; + +/* +================ +dog_bite + +================ +*/ +void() dog_bite = +{ +local vector delta; +local float ldmg; + + if (!self.enemy) + return; + + ai_charge(10); + + if (!CanDamage (self.enemy, self)) + return; + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 100) + return; + + ldmg = (random() + random() + random()) * 8; + T_Damage (self.enemy, self, self, ldmg); +}; + +void() Dog_JumpTouch = +{ + local float ldmg; + + if (self.health <= 0) + return; + + if (other.takedamage) + { + if ( vlen(self.velocity) > 300 ) + { + ldmg = 10 + 10*random(); + T_Damage (other, self, self, ldmg); + } + } + + if (!checkbottom(self)) + { + if (self.flags & FL_ONGROUND) + { // jump randomly to not get hung up +//dprint ("popjump\n"); + self.touch = SUB_Null; + self.think = dog_leap1; + self.nextthink = time + 0.1; + +// self.velocity_x = (random() - 0.5) * 600; +// self.velocity_y = (random() - 0.5) * 600; +// self.velocity_z = 200; +// self.flags = self.flags - FL_ONGROUND; + } + return; // not on ground yet + } + + self.touch = SUB_Null; + self.think = dog_run1; + self.nextthink = time + 0.1; +}; + + +void() dog_stand1 =[ $stand1, dog_stand2 ] {ai_stand();}; +void() dog_stand2 =[ $stand2, dog_stand3 ] {ai_stand();}; +void() dog_stand3 =[ $stand3, dog_stand4 ] {ai_stand();}; +void() dog_stand4 =[ $stand4, dog_stand5 ] {ai_stand();}; +void() dog_stand5 =[ $stand5, dog_stand6 ] {ai_stand();}; +void() dog_stand6 =[ $stand6, dog_stand7 ] {ai_stand();}; +void() dog_stand7 =[ $stand7, dog_stand8 ] {ai_stand();}; +void() dog_stand8 =[ $stand8, dog_stand9 ] {ai_stand();}; +void() dog_stand9 =[ $stand9, dog_stand1 ] {ai_stand();}; + +void() dog_walk1 =[ $walk1 , dog_walk2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE); +ai_walk(8);}; +void() dog_walk2 =[ $walk2 , dog_walk3 ] {ai_walk(8);}; +void() dog_walk3 =[ $walk3 , dog_walk4 ] {ai_walk(8);}; +void() dog_walk4 =[ $walk4 , dog_walk5 ] {ai_walk(8);}; +void() dog_walk5 =[ $walk5 , dog_walk6 ] {ai_walk(8);}; +void() dog_walk6 =[ $walk6 , dog_walk7 ] {ai_walk(8);}; +void() dog_walk7 =[ $walk7 , dog_walk8 ] {ai_walk(8);}; +void() dog_walk8 =[ $walk8 , dog_walk1 ] {ai_walk(8);}; + +void() dog_run1 =[ $run1 , dog_run2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE); +ai_run(16);}; +void() dog_run2 =[ $run2 , dog_run3 ] {ai_run(32);}; +void() dog_run3 =[ $run3 , dog_run4 ] {ai_run(32);}; +void() dog_run4 =[ $run4 , dog_run5 ] {ai_run(20);}; +void() dog_run5 =[ $run5 , dog_run6 ] {ai_run(64);}; +void() dog_run6 =[ $run6 , dog_run7 ] {ai_run(32);}; +void() dog_run7 =[ $run7 , dog_run8 ] {ai_run(16);}; +void() dog_run8 =[ $run8 , dog_run9 ] {ai_run(32);}; +void() dog_run9 =[ $run9 , dog_run10 ] {ai_run(32);}; +void() dog_run10 =[ $run10 , dog_run11 ] {ai_run(20);}; +void() dog_run11 =[ $run11 , dog_run12 ] {ai_run(64);}; +void() dog_run12 =[ $run12 , dog_run1 ] {ai_run(32);}; + +void() dog_atta1 =[ $attack1, dog_atta2 ] {ai_charge(10);}; +void() dog_atta2 =[ $attack2, dog_atta3 ] {ai_charge(10);}; +void() dog_atta3 =[ $attack3, dog_atta4 ] {ai_charge(10);}; +void() dog_atta4 =[ $attack4, dog_atta5 ] { +sound (self, CHAN_VOICE, "dog/dattack1.wav", 1, ATTN_NORM); +dog_bite();}; +void() dog_atta5 =[ $attack5, dog_atta6 ] {ai_charge(10);}; +void() dog_atta6 =[ $attack6, dog_atta7 ] {ai_charge(10);}; +void() dog_atta7 =[ $attack7, dog_atta8 ] {ai_charge(10);}; +void() dog_atta8 =[ $attack8, dog_run1 ] {ai_charge(10);}; + +void() dog_leap1 =[ $leap1, dog_leap2 ] {ai_face();}; +void() dog_leap2 =[ $leap2, dog_leap3 ] +{ + ai_face(); + + self.touch = Dog_JumpTouch; + makevectors (self.angles); + self.origin_z = self.origin_z + 1; + self.velocity = v_forward * 300 + '0 0 200'; + if (self.flags & FL_ONGROUND) + self.flags = self.flags - FL_ONGROUND; +}; + +void() dog_leap3 =[ $leap3, dog_leap4 ] {}; +void() dog_leap4 =[ $leap4, dog_leap5 ] {}; +void() dog_leap5 =[ $leap5, dog_leap6 ] {}; +void() dog_leap6 =[ $leap6, dog_leap7 ] {}; +void() dog_leap7 =[ $leap7, dog_leap8 ] {}; +void() dog_leap8 =[ $leap8, dog_leap9 ] {}; +void() dog_leap9 =[ $leap9, dog_leap9 ] {}; + +void() dog_pain1 =[ $pain1 , dog_pain2 ] {}; +void() dog_pain2 =[ $pain2 , dog_pain3 ] {}; +void() dog_pain3 =[ $pain3 , dog_pain4 ] {}; +void() dog_pain4 =[ $pain4 , dog_pain5 ] {}; +void() dog_pain5 =[ $pain5 , dog_pain6 ] {}; +void() dog_pain6 =[ $pain6 , dog_run1 ] {}; + +void() dog_painb1 =[ $painb1 , dog_painb2 ] {}; +void() dog_painb2 =[ $painb2 , dog_painb3 ] {}; +void() dog_painb3 =[ $painb3 , dog_painb4 ] {ai_pain(4);}; +void() dog_painb4 =[ $painb4 , dog_painb5 ] {ai_pain(12);}; +void() dog_painb5 =[ $painb5 , dog_painb6 ] {ai_pain(12);}; +void() dog_painb6 =[ $painb6 , dog_painb7 ] {ai_pain(2);}; +void() dog_painb7 =[ $painb7 , dog_painb8 ] {}; +void() dog_painb8 =[ $painb8 , dog_painb9 ] {ai_pain(4);}; +void() dog_painb9 =[ $painb9 , dog_painb10 ] {}; +void() dog_painb10 =[ $painb10 , dog_painb11 ] {ai_pain(10);}; +void() dog_painb11 =[ $painb11 , dog_painb12 ] {}; +void() dog_painb12 =[ $painb12 , dog_painb13 ] {}; +void() dog_painb13 =[ $painb13 , dog_painb14 ] {}; +void() dog_painb14 =[ $painb14 , dog_painb15 ] {}; +void() dog_painb15 =[ $painb15 , dog_painb16 ] {}; +void() dog_painb16 =[ $painb16 , dog_run1 ] {}; + +void() dog_pain = +{ + sound (self, CHAN_VOICE, "dog/dpain1.wav", 1, ATTN_NORM); + + if (random() > 0.5) + dog_pain1 (); + else + dog_painb1 (); +}; + +void() dog_die1 =[ $death1, dog_die2 ] {}; +void() dog_die2 =[ $death2, dog_die3 ] {}; +void() dog_die3 =[ $death3, dog_die4 ] {}; +void() dog_die4 =[ $death4, dog_die5 ] {}; +void() dog_die5 =[ $death5, dog_die6 ] {}; +void() dog_die6 =[ $death6, dog_die7 ] {}; +void() dog_die7 =[ $death7, dog_die8 ] {}; +void() dog_die8 =[ $death8, dog_die9 ] {}; +void() dog_die9 =[ $death9, dog_die9 ] {}; + +void() dog_dieb1 =[ $deathb1, dog_dieb2 ] {}; +void() dog_dieb2 =[ $deathb2, dog_dieb3 ] {}; +void() dog_dieb3 =[ $deathb3, dog_dieb4 ] {}; +void() dog_dieb4 =[ $deathb4, dog_dieb5 ] {}; +void() dog_dieb5 =[ $deathb5, dog_dieb6 ] {}; +void() dog_dieb6 =[ $deathb6, dog_dieb7 ] {}; +void() dog_dieb7 =[ $deathb7, dog_dieb8 ] {}; +void() dog_dieb8 =[ $deathb8, dog_dieb9 ] {}; +void() dog_dieb9 =[ $deathb9, dog_dieb9 ] {}; + + +void() dog_die = +{ +// check for gib + if (self.health < -35) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowGib ("progs/gib3.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + ThrowHead ("progs/h_dog.mdl", self.health); + return; + } + +// regular death + sound (self, CHAN_VOICE, "dog/ddeath.wav", 1, ATTN_NORM); + self.solid = SOLID_NOT; + + if (random() > 0.5) + dog_die1 (); + else + dog_dieb1 (); +}; + +//============================================================================ + +/* +============== +CheckDogMelee + +Returns TRUE if a melee attack would hit right now +============== +*/ +float() CheckDogMelee = +{ + if (enemy_range == RANGE_MELEE) + { // FIXME: check canreach + self.attack_state = AS_MELEE; + return TRUE; + } + return FALSE; +}; + +/* +============== +CheckDogJump + +============== +*/ +float() CheckDogJump = +{ + local vector dist; + local float d; + + if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z + + 0.75 * self.enemy.size_z) + return FALSE; + + if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z + + 0.25 * self.enemy.size_z) + return FALSE; + + dist = self.enemy.origin - self.origin; + dist_z = 0; + + d = vlen(dist); + + if (d < 80) + return FALSE; + + if (d > 150) + return FALSE; + + return TRUE; +}; + +float() DogCheckAttack = +{ + local vector vec; + +// if close enough for slashing, go for it + if (CheckDogMelee ()) + { + self.attack_state = AS_MELEE; + return TRUE; + } + + if (CheckDogJump ()) + { + self.attack_state = AS_MISSILE; + return TRUE; + } + + return FALSE; +}; + + +//=========================================================================== + +/*QUAK-ED monster_dog (1 0 0) (-32 -32 -24) (32 32 40) Ambush +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() monster_dog = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/h_dog.mdl"); + precache_model ("progs/dog.mdl"); + + precache_sound ("dog/dattack1.wav"); + precache_sound ("dog/ddeath.wav"); + precache_sound ("dog/dpain1.wav"); + precache_sound ("dog/dsight.wav"); + precache_sound ("dog/idle.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/dog.mdl"); + + setsize (self, '-32 -32 -24', '32 32 40'); + self.health = 25; + + self.th_stand = dog_stand1; + self.th_walk = dog_walk1; + self.th_run = dog_run1; + self.th_pain = dog_pain; + self.th_die = dog_die; + self.th_melee = dog_atta1; + self.th_missile = dog_leap1; + + walkmonster_start(); +}; + diff --git a/doors.hc b/doors.hc new file mode 100644 index 0000000..1e2b1b4 --- /dev/null +++ b/doors.hc @@ -0,0 +1,1798 @@ +/* + * $Header: /HexenWorld/Siege/Doors.hc 12 6/01/98 2:49a Mgummelt $ + */ + +float DOOR_START_OPEN = 1; +float REVERSE = 2; +float DOOR_DONT_LINK = 4; +float DOOR_TOGGLE = 8; +float DOOR_SLIDE = 16; +float DOOR_NORMAL = 32; +float DOOR_REMOVE_PP = 64; +float DOOR_NO_PP = 128; + +/* +Doors are similar to buttons, but can spawn a fat trigger field around them +to open without a touch, and they link together to form simultanious +double/quad doors. + +Door.owner is the master door. If there is only one door, it points to itself. +If multiple doors, all will point to a single one. + +Door.enemy chains from the master door through all doors linked in the chain. +*/ + +void door_hit_bottom(); +void door_hit_top(); + +/* +=========================================================================== +door_slide +=========================================================================== +*/ + +void door_slide_next() +{ + local vector vdestdelta, odelta; + local float len, tspeed;//, len2; + + tspeed = self.speed; + + if(!tspeed) + objerror("No speed is defined!"); + + // Make sure we're not already at the destination + if(self.finaldest == self.origin) + { + self.velocity = '0 0 0'; + if(self.state == STATE_DOWN) + self.think = door_hit_bottom; + else if(self.state == STATE_UP) + self.think = door_hit_top; + self.nextthink = self.ltime + 0.1; + return; + } + + vdestdelta = self.finaldest - self.origin; // Set destdelta to the vector needed to move + odelta = self.origin - self.pos1; + len = vlen(odelta); // Get the length of the vector + + // If the length is this small, just stop + if(vlen(vdestdelta) < 0.1) + { + if(self.state == STATE_DOWN) + door_hit_bottom(); + else if(self.state == STATE_UP) + door_hit_top(); + else + dprint("Bad door state!\n"); + return; + } + + self.nextthink = self.ltime + 0.1; + self.think = door_slide_next; + + tspeed = ((self.speed - (len / 10)) / 20); + + if(tspeed < 2) + { + if(self.state == STATE_DOWN) + SUB_CalcMove(self.finaldest, self.speed, door_hit_bottom); + else if(self.state == STATE_UP) + SUB_CalcMove(self.finaldest, self.speed, door_hit_top); + else + dprint("Bad door state!\n"); + return; + } + + self.velocity = vdestdelta * tspeed; +} + + +void door_slide(vector tdest) +{ + self.finaldest = tdest; + door_slide_next(); +} + + +/* +=========================================================================== +door_crash +=========================================================================== +*/ + +void door_crash_next() +{ + local vector vdestdelta, nextvect, testvect; + local vector tdest; + local float len, nextlen, testlen; + local float tspeed; + + tdest = self.finaldest; + tspeed = self.speed; + + if(!tspeed) + objerror("No speed is defined!"); + + if(tdest == self.origin) + { + self.velocity = '0 0 0'; + if(self.state == STATE_DOWN) + self.think = door_hit_bottom; + else if(self.state == STATE_UP) + self.think = door_hit_top; + else + dprint("Bad door state!\n"); + self.nextthink = self.ltime + 0.1; + return; + } + + // set destdelta to the vector needed to move + vdestdelta = self.finaldest - self.origin; + nextvect = self.pos2 - self.origin; + testvect = self.pos2 - self.finaldest; + + // calculate length of vector + len = vlen (vdestdelta); + nextlen = vlen(nextvect) + 1; + testlen = vlen(testvect); + + if(len < 0.1 || nextlen > testlen) + { + door_hit_bottom; + return; + } + else + { + self.velocity = vdestdelta * (nextlen / len) * 4; + nextvect = self.origin + self.velocity; + nextlen = vlen(nextvect); + if(nextlen >= testlen * 2) + { + SUB_CalcMove(self.finaldest, self.speed * (len / (len / 3)), door_hit_bottom); + return; + } + } + + self.nextthink = self.ltime + 0.1; + self.think = door_crash_next; +} + + +void door_crash(vector tdest) +{ + self.finaldest = tdest; + door_crash_next(); +} + +/* +============================================================================= +THINK FUNCTIONS +============================================================================= +*/ + +void door_go_down(); +void door_go_up(); + +void door_damage() +{ + T_Damage (other, self, self, self.dmg); +} + +void door_blocked() +{ +//FIXME: Rotating doors sem to think they're being blocked +// even if they're rotating down and the object is above them + if(self.wait>-2&&self.strength<=0) + if(self.dmg==666) + { + if(other.classname=="player"&&other.flags2&FL_ALIVE) + { + other.decap=TRUE; + T_Damage (other, self, self, other.health+300); + } + else + T_Damage (other, self, self, other.health+50); + } + else + { + T_Damage (other, self, self, self.dmg); + } + + +//Rotating doors rotating around a x or z axis push you up and in the direction they're turning +/* if(self.strength==2) + { + other.flags(-)FL_ONGROUND; + other.velocity=normalize(self.origin-(other.absmin+other.absmax)*0.5)*100; + } + else*/ if(other.flags&FL_ONGROUND&&(self.movedir_x||self.movedir_z)&&self.strength==1)//&&other.origin_z>self.origin_z + { + other.flags(-)FL_ONGROUND; + other.velocity_z+=self.speed*2; + other.velocity_x-=self.speed*self.movedir_x; + other.velocity_y-=self.speed*self.movedir_z; + } + else + { + other.flags(-)FL_ONGROUND; + other.velocity_z+=10; + } + +// if a door has a negative wait, it would never come back if blocked, +// so let it just squash the object to death real fast + if (other.health>0) + if (self.wait >= 0) + { + if (self.state == STATE_DOWN) + door_go_up (); + else + door_go_down (); + } +} + +void door_blocked_mp() +{ +float do_dmg; + +/* + dprint("Blocked Door: \n"); + dprint(other.classname); + dprint("\n"); + dprintv("Velocity: %s\n",self.velocity); + dprintv("Avelocity: %s\n",self.avelocity); +*/ +//FIXME: Rotating doors seem to think they're being blocked +// even if they're rotating down and the object is above them +// if(self.classname=="door_rotating") +// self.nextthink+=HX_FRAME_TIME;//self.wait? + +/* dprint("door blocked\n"); + dprintf("dmg = %s\n",self.dmg); + dprintf("strength = %s\n",self.strength); + dprintf("wait = %s\n",self.wait); + dprint("other = "); + dprint(other.classname); + dprint("\n");*/ + if(self.dmg==-1) + { + if(other.classname=="player" && other.flags2&FL_ALIVE) + { + if (self.wait >= 0) + { + if (self.state == STATE_DOWN) + door_go_up (); + else + door_go_down (); + } + return; + } + else + do_dmg=2; + } + else + do_dmg=self.dmg; + +// dprintf("Door dmg = %s\n",do_dmg); + if(self.wait>-2)//&&self.strength<=0) + { + if(do_dmg==666) + { + if(other.classname=="player"&&other.flags2&FL_ALIVE) + { + other.decap=TRUE; + T_Damage (other, self, self, other.health+300); + } + else + T_Damage (other, self, self, other.health+50); + } + else + { +// dprintf("crushing- %s\n",do_dmg); + T_Damage (other, self, self, do_dmg);//FIXME: Rotating doors get stuck open and never try to return + } + } +// else +// dprint("Door wait <= -2\n"); + +//Rotating doors rotating around a x or z axis push you up and in the direction they're turning +/* if(self.strength==2) + { + other.flags(-)FL_ONGROUND; + other.velocity=normalize(self.origin-(other.absmin+other.absmax)*0.5)*100; + } + else*/ + +/*NOT in MP maps? + if(other.flags&FL_ONGROUND&&(self.movedir_x||self.movedir_z)&&self.strength==1)//&&other.origin_z>self.origin_z + {//This is not neccessary anymore + other.flags(-)FL_ONGROUND; + other.velocity_z+=self.speed*2; + other.velocity_x-=self.speed*self.movedir_x; + other.velocity_y-=self.speed*self.movedir_z; + } + else + { + other.flags(-)FL_ONGROUND; + other.velocity_z+=10; + } +*/ +// if a door has a negative wait, it would never come back if blocked, +// so let it just squash the object to death real fast + if (other.health>0) + if (self.wait >= 0)//&&self.wait!=1.5) + { + if (self.state == STATE_DOWN) + { + // dprint("Going up...\n"); + door_go_up (); + } + else + { + // dprint("Going down...\n"); + door_go_down (); + } + } +} + + +void door_hit_top() +{ + self.velocity = '0 0 0'; + sound (self,CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.effects(-)EF_UPDATESOUND; + self.state = STATE_TOP; + + if (self.spawnflags & DOOR_TOGGLE) + return; // don't come down automatically + + if(self.wait== -2) + self.th_die(); + else if(self.wait== -1) + self.nextthink = -1; + else + { + self.think = door_go_down; + self.nextthink = self.ltime + self.wait; + } +} + +void door_hit_bottom() +{ + self.velocity = '0 0 0'; + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.effects(-)EF_UPDATESOUND; + self.state = STATE_BOTTOM; +} + +void door_go_down() +{ +string hold_target; + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise2, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + if(!self.thingtype && self.max_health) + { + self.takedamage = DAMAGE_YES; + self.health = self.max_health; + } + + self.state = STATE_DOWN; + + if(self.classname == "door") + { +// dprintv("rotation: %s\n",self.v_angle); + if(self.spawnflags & DOOR_SLIDE) + door_slide(self.pos1); + else if(self.spawnflags & DOOR_NORMAL) + if(self.v_angle!='0 0 0') + if(self.speed) + if(self.anglespeed) + SUB_CalcMoveAndAngleInit (self.pos1, self.speed, self.o_angle, self.anglespeed, door_hit_bottom,FALSE); + else + SUB_CalcMoveAndAngleInit (self.pos1, self.speed, self.o_angle, self.anglespeed, door_hit_bottom,TRUE); + else + SUB_CalcAngleMove(self.o_angle, self.anglespeed, door_hit_bottom); + else + SUB_CalcMove(self.pos1, self.speed, door_hit_bottom); + else + door_crash(self.pos1); + } + else if (self.classname == "door_rotating") + SUB_CalcAngleMove(self.pos1, self.speed, door_hit_bottom); + + if(self.close_target!="") + {//Use second target when closing + hold_target=self.target; + self.target=self.close_target; + SUB_UseTargets(); + self.target=hold_target; + } +} + + +void new_movedir (vector movin,float dir) +{ + self.movedir = movin; + + // check for clockwise rotation + if (dir<0) + self.movedir = self.movedir * -1; + + self.pos1 = self.angles; + self.pos2 = self.angles + self.movedir * self.dflags; +} + +void door_go_up() +{ + if(self.state == STATE_UP) /* Already going up */ + { +// dprint("UP: Tried to go up while already going up\n"); + return; + } + + if(self.state == STATE_TOP) /* Reset top wait time */ + { + self.nextthink = self.ltime + self.wait; +// dprint("TOP: Tried to go up while already at top\n"); + return; + } + + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise2, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + self.state = STATE_UP; + + if(self.classname == "door") + { + if(self.spawnflags & DOOR_NORMAL) + { + if(self.v_angle!='0 0 0') + { + if(self.speed) + { + if(self.anglespeed) + SUB_CalcMoveAndAngleInit (self.pos2, self.speed, self.v_angle, self.anglespeed, door_hit_top,FALSE); + else + SUB_CalcMoveAndAngleInit (self.pos2, self.speed, self.v_angle, self.anglespeed, door_hit_top,TRUE); + } + else + SUB_CalcAngleMove(self.v_angle, self.anglespeed, door_hit_top); + } + else + SUB_CalcMove(self.pos2, self.speed, door_hit_top); + } + else + door_slide(self.pos2); + } + else if(self.classname == "door_rotating") + SUB_CalcAngleMove(self.pos2, self.speed, door_hit_top); + + SUB_UseTargets(); +} + + +/* +============================================================================= + +ACTIVATION FUNCTIONS + +============================================================================= +*/ + +void door_fire() +{ +entity oself; +entity starte; + +// if(self.wait<=-1 || self.wait==1.5)//not supposed to return +// if(self.velocity!='0 0 0'||self.avelocity!='0 0 0')//Moving +// return; + + if (self.owner != self) + objerror ("door_fire: self.owner != self"); + + self.no_puzzle_msg = 0; + +// play use key sound + + self.message = 0; // no more message + oself = self; + + if (self.spawnflags & DOOR_TOGGLE) + { + if (self.state == STATE_UP || self.state == STATE_TOP) + { + starte = self; + do + { + door_go_down (); + self = self.enemy; + } while ( (self != starte) && (self != world) ); + self = oself; + return; + } + } + +// trigger all paired doors + starte = self; + do + { + door_go_up (); + self = self.enemy; + } while ( (self != starte) && (self != world) ); + self = oself; +} + + +/* + * door_use() -- Called whenever a door is opened. + */ + +void door_use() +{ +entity oself; + + + /* + dprint("Door Used by: "); + dprint(other.classname); + dprint("\n"); + dprint("Door's Activator: "); + dprint(activator.classname); + dprint("\n"); +*/ + + if(self.inactive) + { + // dprint("Door not active\n"); + return; + } + + self.message = 0; // door messages are for touch only + self.owner.message = 0; + self.enemy.message = 0; + oself = self; + self = self.owner; + door_fire (); + self = oself; +} + + +// defined in triggers.hc +float check_puzzle_pieces(entity client, float remove_pieces, float inverse); + +/* + * door_trigger_touch() -- Called when someone touches a door. + */ + +void door_trigger_touch() +{ + entity door; + string temp; + float removepp, inversepp; + +// if(!other.flags2&FL_ALIVE) +// return; + + if(!other.flags&FL_CLIENT&&!other.flags&FL_MONSTER) + return; + + if(other.flags&FL_MONSTER&&world.spawnflags&MISSIONPACK) + return; + + if(time < self.attack_finished) + return; + + door = self; + self = self.owner; + if(!deathmatch) + { + removepp = (self.spawnflags & DOOR_REMOVE_PP); + inversepp = (self.spawnflags & DOOR_NO_PP); + + if (!check_puzzle_pieces(other,removepp,inversepp)) + { + if (self.no_puzzle_msg && !deathmatch) + { + temp = getstring(self.no_puzzle_msg); + centerprint (other, temp); + door.attack_finished = time + 2; + } + return; + } + } + + self.attack_finished = time + 1; + + activator = other; + door_use(); +} + + +/* + * door_killed() -- Used to open doors that open when shot. + */ + +void door_killed() +{ + local entity oself; + + oself = self; + self = self.owner; + self.health = self.max_health; + self.takedamage = DAMAGE_NO; // wil be reset upon return + door_use(); + self = oself; +} + + +/* + * door_touch() -- Prints messages and opens key doors. + */ + +void door_touch() +{ + string temp; + float removepp, inversepp; + +// dprint("Door hit!\n"); + // if(!other.flags2&FL_ALIVE) +// return; + + if(self.siege_team) + if(other.siege_team!=self.siege_team) + return; + + if(!other.flags&FL_CLIENT&&!other.flags&FL_MONSTER) + return; + + if(other.flags&FL_MONSTER&&world.spawnflags&MISSIONPACK) + return; + + if(self.dmg==666&&(self.velocity!='0 0 0'||self.avelocity!='0 0 0')) + { + if(other.classname=="player"&&other.flags2&FL_ALIVE) + { + other.decap=TRUE; + T_Damage (other, self, self, other.health+300); + } + else + T_Damage (other, self, self, other.health+50); + } + + if(self.owner.attack_finished > time) + return; + + if (self.owner) + self.owner.attack_finished = time + 2; + + if(self.owner.message != 0 && !deathmatch && self.owner != world) + { + temp = getstring(self.owner.message); + centerprint (other, temp); + sound (other, CHAN_UPDATE+PHS_OVERRIDE_R, "misc/comm.wav", 1, ATTN_NORM); + } + +// key door stuff + + if (!self.puzzle_piece_1 && !self.puzzle_piece_2 && !self.puzzle_piece_3 && !self.puzzle_piece_4) + return; + +// FIXME: blink key on player's status bar + + removepp = (self.spawnflags & DOOR_REMOVE_PP); + inversepp = (self.spawnflags & DOOR_NO_PP); + + if (!check_puzzle_pieces(other,removepp,inversepp)) + { + if (self.no_puzzle_msg && !deathmatch) + { + temp = getstring(self.no_puzzle_msg); + centerprint (other, temp); + } + return; + } + + self.touch = SUB_Null; + if (self.enemy) + self.enemy.touch = SUB_Null; // get paired door + door_use (); +} + + + +/* +============================================================================= + +SPAWNING FUNCTIONS + +============================================================================= +*/ + + +entity spawn_field(vector fmins, vector fmaxs, entity door) +{//FIXME: THIS ENTITY NEEDS TO REMOVE ITSELF IF IT'S OWNER IS + //REMOVED! +entity trigger; +vector t1, t2; + + trigger = spawn(); + trigger.movetype = MOVETYPE_NONE; + trigger.solid = SOLID_TRIGGER; + trigger.owner = door; + trigger.touch = door_trigger_touch; + + t1 = fmins; + t2 = fmaxs; +// if (door.classname == "door") +// { +// if(self.v_angle!='0 0 0') +// { + t1 += door.origin; + t2 += door.origin; + setsize (trigger, t1 - '60 60 8', t2 + '60 60 8'); +/* } + else + setsize (trigger, t1 - '60 60 8', t2 + '60 60 8'); + } + else if (door.classname == "door_rotating") + { + t1 += door.origin; + t2 += door.origin; + setsize (trigger, t1 - '60 60 8', t2 + '60 60 8'); + } +*/ return (trigger); +} + +float EntitiesTouching(entity e1, entity e2) +{ + local vector e1max, e1min, e2max, e2min; + + //Rotating door's mins and maxs aren't based on their world positions, + //so the origin needs to be applied to make sure they are checking their + //real positions + + if (e1.classname == "door_rotating"||(e1.classname=="door"&&e1.v_angle!='0 0 0')) + { + e1max = e1.maxs + e1.origin; + e1min = e1.mins + e1.origin; + e2max = e2.maxs + e2.origin; + e2min = e2.mins + e2.origin; + } + else + { + e1max = e1.maxs; + e1min = e1.mins; + e2max = e2.maxs; + e2min = e2.mins; + } + + if (e1min_x > e2max_x) + return FALSE; + if (e1min_y > e2max_y) + return FALSE; + if (e1min_z > e2max_z) + return FALSE; + if (e1max_x < e2min_x) + return FALSE; + if (e1max_y < e2min_y) + return FALSE; + if (e1max_z < e2min_z) + return FALSE; + return TRUE; +} + + +/* + * LinkDoors() + */ + +void LinkDoors() +{ +entity t, starte; +vector cmins, cmaxs; + + if (self.enemy) + return; // already linked by another door + + if (self.spawnflags & 4) + { + self.owner = self.enemy = self; + return; // don't want to link this door + } + + cmins = self.mins; + cmaxs = self.maxs; + + starte = self; + t = self; + + do + { + self.owner = starte; // master door + + if (!self.thingtype && self.health) + starte.health = self.health; + if (self.targetname) + starte.targetname = self.targetname; + if (self.message != 0) + starte.message = self.message; + + t = find (t, classname, self.classname); + if (!t) + { + self.enemy = starte; // make the chain a loop + + // shootable, fired, or key doors just needed the owner/enemy links, + // they don't spawn a field + + self = self.owner; + + if (!self.thingtype && self.health) + return; + if (self.targetname) + return; + if (self.puzzle_piece_1 != string_null || + self.puzzle_piece_2 != string_null || + self.puzzle_piece_3 != string_null || + self.puzzle_piece_4 != string_null) + return; + + self.owner.trigger_field = spawn_field(cmins, cmaxs, self.owner); + + return; + } + + if (EntitiesTouching(self,t)) + { + if (t.enemy) + objerror ("cross connected doors"); + + self.enemy = t; + self = t; + + if (t.mins_x < cmins_x) + cmins_x = t.mins_x; + if (t.mins_y < cmins_y) + cmins_y = t.mins_y; + if (t.mins_z < cmins_z) + cmins_z = t.mins_z; + if (t.maxs_x > cmaxs_x) + cmaxs_x = t.maxs_x; + if (t.maxs_y > cmaxs_y) + cmaxs_y = t.maxs_y; + if (t.maxs_z > cmaxs_z) + cmaxs_z = t.maxs_z; + } + } while (1); +} + +void door_sounds(void) +{ + self.noise3 = "doors/baddoor.wav"; + + if (self.soundtype == 0) // No sound + { + self.noise1 = "misc/null.wav"; + self.noise2 = "misc/null.wav"; + self.noise4 = "misc/null.wav"; + } + else if (self.soundtype == 1) // Big Metal door, swinging + { + precache_sound ("doors/gatestop.wav"); + precache_sound ("doors/gateswng.wav"); + precache_sound ("doors/gatestrt.wav"); + + self.noise1 = "doors/gatestop.wav"; + self.noise2 = "doors/gateswng.wav"; + self.noise4 = "doors/gatestrt.wav"; + } + else if (self.soundtype == 2) // Big Stone Door, sliding + { + precache_sound ("doors/doorstop.wav"); + precache_sound ("doors/stonslid.wav"); + precache_sound ("doors/dorstart.wav"); + + self.noise1 = "doors/doorstop.wav"; + self.noise2 = "doors/stonslid.wav"; + self.noise4 = "doors/dorstart.wav"; + } + else if (self.soundtype == 3) // Big Wood Door, Swinging + { + precache_sound ("doors/swngstop.wav"); + precache_sound ("doors/wdswngbg.wav"); + precache_sound ("doors/dorstart.wav"); + + self.noise1 = "doors/swngstop.wav"; + self.noise2 = "doors/wdswngbg.wav"; + self.noise4 = "doors/dorstart.wav"; + } + else if (self.soundtype == 4) // Normal Wood Door, Swinging + { + precache_sound ("doors/swngstop.wav"); + precache_sound ("doors/wdswngsm.wav"); + precache_sound ("doors/dorstart.wav"); + + self.noise1 = "doors/swngstop.wav"; + self.noise2 = "doors/wdswngsm.wav"; + self.noise4 = "doors/dorstart.wav"; + } + else if (self.soundtype == 5) // Big Wood Door, Sliding + { + precache_sound ("doors/swngstop.wav"); + precache_sound ("doors/woodslid.wav"); + precache_sound ("doors/dorstart.wav"); + + self.noise1 = "doors/swngstop.wav"; + self.noise2 = "doors/woodslid.wav"; + self.noise4 = "doors/dorstart.wav"; + } + else if (self.soundtype == 6) // Drawbridge, Falling and crushing innocent peasants who are + // basically slave labor, who toil away their lives so that the rich upperclass + // can keep busy inbreeding with each other. Damn the aristocracy! Freedom to + // the common man! Burn the castle! Death to the tyrants! + { + precache_sound ("doors/doorstop.wav"); + precache_sound ("doors/drawmove.wav"); + precache_sound ("doors/drawstrt.wav"); + + self.noise1 = "doors/doorstop.wav"; + self.noise2 = "doors/drawmove.wav"; + self.noise4 = "doors/dorstart.wav"; + } + else if (self.soundtype == 7) // Rotating Walkway + { + precache_sound ("doors/doorstop.wav"); + precache_sound ("doors/stonslid.wav"); + precache_sound ("doors/dorstart.wav"); + + self.noise1 = "doors/doorstop.wav"; + self.noise2 = "doors/stonslid.wav"; + self.noise4 = "doors/dorstart.wav"; + } + else if (self.soundtype == 8) // Big Metal door, sliding + { + precache_sound ("doors/mtlstop.wav"); + precache_sound ("doors/mtlslide.wav"); + precache_sound ("doors/mtlstart.wav"); + + self.noise1 = "doors/mtlstop.wav"; + self.noise2 = "doors/mtlslide.wav"; + self.noise4 = "doors/mtlstart.wav"; + } + else if (self.soundtype == 9) // Pendulum + { + precache_sound2 ("doors/penstop.wav"); + precache_sound2 ("doors/penswing.wav"); + precache_sound2 ("doors/penstart.wav"); + + self.noise1 = "doors/penstop.wav"; + self.noise2 = "doors/penswing.wav"; + self.noise4 = "doors/penstart.wav"; + } +} + + +void door_rotate_incr_done() +{ +// if(self.strength==2) +// cvar_set ("sv_gravity", "800"); +} + +void() door_rotate_incr = +{ +vector newvect; + if(self.strength==2) + cvar_set ("sv_gravity", "100"); + + self.dflags=self.flags; + self.flags=0; + + if(self.v_angle!='0 0 0') + { + if(random()>0.5&&self.v_angle_x!=0) + { + self.cnt=self.dflags=self.v_angle_x; + new_movedir('1 0 0',self.cnt); + } + else if(random()>0.5&&self.v_angle_y!=0) + { + self.cnt=self.dflags=self.v_angle_y; + new_movedir('0 1 0',self.cnt); + } + else if(self.v_angle_z!=0) + { + self.cnt=self.dflags=self.v_angle_z; + new_movedir('0 0 1',self.cnt); + } + } + newvect = self.movedir * self.cnt; + + SUB_CalcAngleMove(self.angles + newvect, self.speed, door_rotate_incr_done); +}; + +/*QUAKED func_door (0 .5 .8) ? START_OPEN REVERSE DOOR_DONT_LINK TOGGLE SLIDE NORMAL_MOVE remove_pp no_pp +NOTE: Doors can now be activated and deactivated with the appropriate triggers. +"inactive" set to 1 to start the door deactivated. + +if two doors touch, they are assumed to be connected and operate as a unit. + +-----------------------FIELDS------------------------- +TOGGLE causes the door to wait in both the start and end states for a trigger event. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). + +Key doors are allways wait -1. + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"angle" determines the opening direction +"level" how far (in map units) to move in the specified angle- overrides default movement that is size of door +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. +"health" if set, door must be shot open +"speed" movement speed (100 default), -1 will not move, just rotate +"wait" wait before returning (3 default, -1 = never return) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (2 default) If you make it + 666, it will gib anything it touches, and behead players. + -1 it will hurt other things, but not players +"close_target" secondary target to fire when door closes +"ondeath_target" - only for breakable doors- will activate this target only when it dies + +ROTATING DOORS: MUST HAVE AN ORIGIN BRUSH +"v_angle" Angle to turn, in: pitch yaw roll, '0 0 0' will not rotate, just move (default = '0 0 0') +"anglespeed" how quickly to turn in that direction. no anglespeed will force it to choose one that will synch the completion of the rotation iwth the completion of the move. (default = 0) +"strength" When set to 1, it will throw something if it gets in the way + +"soundtype" +0) no sound +1) Big metal door, swinging +2) Big stone door, sliding +3) Big wood door, swinging +4) Normal wood door, swinging +5) Big wood door, sliding +6) Drawbridge +7) Rotating walkway +8) Big metal door, sliding +9) Pendulum swinging + +Puzzle Pieces (use the puzzle_id value from the pieces) + puzzle_piece_1 + puzzle_piece_2 + puzzle_piece_3 + puzzle_piece_4 + no_puzzle_msg: message when player doesn't have the right pieces +-------------------------------------------------------- + +*/ +void func_door() +{ +float movedist, num_axes; + door_sounds(); + + SetMovedir (); + // check for clockwise rotation + if (self.spawnflags & REVERSE) + { + self.movedir = self.movedir * -1; + self.v_angle = self.v_angle * -1; + } + + self.max_health = self.health; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + self.classname = self.netname = "door"; + + self.use = door_use; + + if (self.abslight) + self.drawflags = self.drawflags | MLS_ABSLIGHT; + + if (self.speed==-1) + self.speed=0; + else if(!self.speed) + self.speed = 100; + + if (!self.wait) + self.wait = 3; + + if (!self.lip) + self.lip = 8; + + if(world.spawnflags&MISSIONPACK) + self.blocked = door_blocked_mp; + else + self.blocked = door_blocked; + if (!self.dmg) +// self.dmg = -1; + self.dmg = 2; + + self.pos1 = self.origin; +// dprintf("Worldspawn.spawnflags = %s\n",world.spawnflags); + if(world.spawnflags&MISSIONPACK) + { +// dprint("Using new door code\n"); + if(self.level) + movedist = self.level - self.lip; + else + { + //was: movedist=fabs(self.movedir*self.size) - self.lip; +// dprintv("Door movedir = %s\n",self.movedir); +// dprintv("Door size = %s\n",self.size); + num_axes=0; + movedist=0; + if(fabs(self.movedir_x)>0.001) + { +// dprint("X axis\n"); + movedist+=fabs(self.movedir_x*self.size_x); + num_axes+=1; + } + if(fabs(self.movedir_y)>0.001) + { +// dprint("Y axis\n"); + movedist+=fabs(self.movedir_y*self.size_y); + num_axes+=1; + } + if(fabs(self.movedir_z)>0.001) + { +// dprint("Z axis\n"); + movedist+=fabs(self.movedir_z*self.size_z); + num_axes+=1; + } + movedist=movedist/num_axes - self.lip; +// dprintf("Door movedist = %s\n",movedist); + } + self.pos2 = self.pos1 + self.movedir*movedist; + } + else + { +// dprint("Using old door code\n"); + if(self.level) + self.pos2 = self.pos1 + self.movedir*(self.level - self.lip); + else + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + } +// dprintv("Pos1: %s\n",self.pos1); +// dprintv("Pos2: %s\n",self.pos2); + if(self.v_angle!='0 0 0') + { + self.o_angle=self.angles; + self.v_angle+=self.angles; + } + + if(self.wait== -2||self.strength==1) + { + self.th_die = chunk_death; +// self.takedamage = DAMAGE_YES; + if (!self.health) + { + if ((self.thingtype == THINGTYPE_GLASS) || (self.thingtype == THINGTYPE_CLEARGLASS)) + self.max_health = self.health = 25; + else if ((self.thingtype == THINGTYPE_GREYSTONE) || (self.thingtype == THINGTYPE_BROWNSTONE)||self.thingtype==THINGTYPE_DIRT) + self.max_health = self.health = 75; + else if (self.thingtype == THINGTYPE_WOOD) + self.max_health = self.health = 50; + else if (self.thingtype == THINGTYPE_METAL) + self.max_health = self.health = 100; + else if (self.thingtype == THINGTYPE_FLESH) + self.max_health = self.health = 30; + else + self.max_health = self.health = 25; + } + } + +// DOOR_START_OPEN is to allow an entity to be lighted in the closed position +// but spawn in the open position + if (self.spawnflags & DOOR_START_OPEN) + { + if(self.v_angle!='0 0 0') + { + self.angles = self.v_angle; + self.v_angle = self.o_angle; + self.o_angle = self.angles; + } + setorigin (self, self.pos2); + self.pos2 = self.pos1; + self.pos1 = self.origin; + } + + self.state = STATE_BOTTOM; + + if (self.health) + { + self.takedamage = DAMAGE_YES; + if(self.strength!=1) + self.th_die =self.th_pain= door_killed; + } + + if (self.puzzle_piece_1 != string_null || + self.puzzle_piece_2 != string_null || + self.puzzle_piece_3 != string_null || + self.puzzle_piece_4 != string_null) + self.wait = -1; + + self.touch = door_touch; + +// LinkDoors can't be done until all of the doors have been spawned, so +// the sizes can be detected properly. + self.think = LinkDoors; + self.nextthink = self.ltime + 0.1; + + if (self.cnt) + { + self.touch = SUB_Null; + self.use = door_rotate_incr; + } +} + + +/*QUAKED func_door_smashing (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE SLIDE NORMAL_MOVE remove_pp no_pp +NOTE: Doors can now be activated and deactivated with the appropriate triggers. +"inactive" set to 1 to start the door deactivated. + +if two doors touch, they are assumed to be connected and operate as a unit. + +-----------------------FIELDS------------------------- +TOGGLE causes the door to wait in both the start and end states for a trigger event. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). + +Key doors are allways wait -1. + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"angle" determines the opening direction +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (2 default) +"close_target" secondary target to fire when door closes + + +"soundtype" +0) no sound +1) Big metal door, swinging +2) Big stone door, sliding +3) Big wood door, swinging +4) Normal wood door, swinging +5) Big wood door, sliding +6) Drawbridge +7) Rotating walkway +8) Big metal door, sliding +9) Pendulum swinging + + + +Puzzle Pieces (use the puzzle_id value from the pieces) + puzzle_piece_1 + puzzle_piece_2 + puzzle_piece_3 + puzzle_piece_4 + no_puzzle_msg: message when player doesn't have the right pieces +-------------------------------------------------------- +void func_door_smashing() +{ + door_sounds(); + + SetMovedir (); + + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + self.classname = "door"; + + if(world.spawnflags&MISSIONPACK) + self.blocked = door_blocked_mp; + else + self.blocked = door_blocked; + self.use = door_use; + + if (!self.speed) + self.speed = 100; + if (!self.wait) + self.wait = 3; + if (!self.lip) + self.lip = 8; + if (!self.dmg) + self.dmg = 2; + + self.pos1 = self.origin; + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + +// DOOR_START_OPEN is to allow an entity to be lighted in the closed position +// but spawn in the open position + if (self.spawnflags & DOOR_START_OPEN) + { + setorigin (self, self.pos2); + self.pos2 = self.pos1; + self.pos1 = self.origin; + } + + self.state = STATE_BOTTOM; + self.takedamage = DAMAGE_YES; + self.th_die = chunk_death; + + if(self.soundtype == 1) + { + self.thingtype = THINGTYPE_GREYSTONE; + self.max_health = self.health = 75; + } + else if(self.soundtype == 4) + { + self.thingtype = THINGTYPE_METAL; + self.max_health = self.health = 100; + } + else { + self.thingtype = THINGTYPE_WOOD; + self.max_health = self.health = 50; + } + + self.touch = door_touch; + +// LinkDoors can't be done until all of the doors have been spawned, so +// the sizes can be detected properly. + self.think = LinkDoors; + self.nextthink = self.ltime + 0.1; +}*/ + + + +/* +============================================================================= + +SECRET DOORS + +============================================================================= +*/ + +void fd_secret_move1(); +void fd_secret_move2(); +void fd_secret_move3(); +void fd_secret_move4(); +void fd_secret_move5(); +void fd_secret_move6(); +void fd_secret_done(); + +float SECRET_OPEN_ONCE = 1; // stays open +float SECRET_1ST_LEFT = 2; // 1st move is left of arrow +float SECRET_1ST_DOWN = 4; // 1st move is down from arrow +float SECRET_NO_SHOOT = 8; // only opened by trigger +float SECRET_YES_SHOOT = 16; // shootable even if targeted + + +void fd_secret_use() +{ + local float temp; + + self.health = 10000; + + // exit if still moving around... + if(self.origin != self.oldorigin) + return; + + if(self.inactive) + return; + + self.message = 0; // no more message + + SUB_UseTargets(); // fire all targets / killtargets + + if(!self.spawnflags & SECRET_NO_SHOOT) + { + self.th_pain = SUB_Null; + self.takedamage = DAMAGE_NO; + } + self.velocity = '0 0 0'; + + // Make a sound, wait a little... + + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.effects(-)EF_UPDATESOUND; + self.nextthink = self.ltime + 0.1; + + temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1 + makevectors(self.mangle); + + if(!self.t_width) + { + if (self.spawnflags & SECRET_1ST_DOWN) + self. t_width = fabs(v_up * self.size); + else + self. t_width = fabs(v_right * self.size); + } + + if (!self.t_length) + self. t_length = fabs(v_forward * self.size); + + if (self.spawnflags & SECRET_1ST_DOWN) + self.dest1 = self.origin - v_up * self.t_width; + else + self.dest1 = self.origin + v_right * (self.t_width * temp); + + self.dest2 = self.dest1 + v_forward * self.t_length; + SUB_CalcMove(self.dest1, self.speed, fd_secret_move1); + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise2, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; +} + + +/* Wait after the first movement... */ + +void fd_secret_move1() +{ + self.nextthink = self.ltime + 1; + self.think = fd_secret_move2; + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise3, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; +} + + +/* Start moving sideways with sound... */ + +void fd_secret_move2() +{ + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise2, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + SUB_CalcMove(self.dest2, self.speed, fd_secret_move3); +} + + +/* Wait here until it's time to go back... */ + +void fd_secret_move3() +{ + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise3, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + if(!self.spawnflags & SECRET_OPEN_ONCE) + { + self.nextthink = self.ltime + self.wait; + self.think = fd_secret_move4; + } +} + + +/* Move backward... */ + +void fd_secret_move4() +{ + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise2, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + SUB_CalcMove(self.dest1, self.speed, fd_secret_move5); +} + + +/* Wait for one second... */ + +void fd_secret_move5() +{ + self.nextthink = self.ltime + 1; + self.think = fd_secret_move6; + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise3, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; +} + +void fd_secret_move6() +{ + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise2, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done); +} + +void fd_secret_done() +{ + if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT) + { + self.health = 10000; + self.takedamage = DAMAGE_YES; + self.th_pain = fd_secret_use; + } + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise3, 1, ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; +} + +void secret_blocked() +{ + if (time < self.attack_finished) + return; + self.attack_finished = time + 0.5; + T_Damage (other, self, self, self.dmg); +} + + +/* + * secret_touch() -- Prints messages. + */ + +void secret_touch() +{ + string s; + + if (other.classname != "player") + return; + + if (self.attack_finished > time) + return; + + self.attack_finished = time + 2; + + if (self.message) + { + s = getstring(self.message); + centerprint (other, s); + sound (other, CHAN_BODY, "misc/comm.wav", 1, ATTN_NORM); + } +} + + +/*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot x remove_pp no_pp +NOTE: Doors can now be activated and deactivated with the appropriate triggers. +"inactive" set to 1 to start the door deactivated. + +Basic secret door. Slides back, then to the side. Angle determines direction. +-----------------------FIELDS------------------------- +wait = # of seconds before coming back +1st_left = 1st move is left of arrow +1st_down = 1st move is down from arrow +always_shoot = even if targeted, keep shootable +t_width = override WIDTH to move back (or height if going down) +t_length = override LENGTH to move sideways +"dmg" damage to inflict when blocked (2 default) +"close_target" secondary target to fire when door closes + +If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage. + +"soundtype" +0) no sound +1) Big metal door, swinging +2) Big stone door, sliding +3) Big wood door, swinging +4) Normal wood door, swinging +5) Big wood door, sliding +6) Drawbridge +7) Rotating walkway +8) Big metal door, sliding +9) Pendulum swinging + + +Puzzle Pieces (use the puzzle_id value from the pieces) + puzzle_piece_1 + puzzle_piece_2 + puzzle_piece_3 + puzzle_piece_4 + no_puzzle_msg: message when player doesn't have the right pieces +-------------------------------------------------------- +*/ + +void func_door_secret() +{ + door_sounds(); + + if (!self.dmg) + self.dmg = 2; + + // Magic formula... + self.mangle = self.angles; + self.angles = '0 0 0'; + if(world.spawnflags&MISSIONPACK) + { + if(self.mangle=='0 -1 0') + { + self.mangle='-90 0 0'; + } + else if(self.mangle=='0 -2 0') + { + self.mangle='90 0 0'; + } + } + + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + self.classname = self.netname = "door"; + setmodel (self, self.model); + setorigin (self, self.origin); + + self.touch = secret_touch; + self.blocked = secret_blocked; + self.speed = 50; + self.use = fd_secret_use; + if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT) + { + self.health = 10000; + self.takedamage = DAMAGE_YES; + self.th_pain = fd_secret_use; + self.th_die = fd_secret_use; + } + self.oldorigin = self.origin; + if (!self.wait) + self.wait = 5; // 5 seconds before closing +} + +/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE DOOR_DONT_LINK remove_pp no_pp TOGGLE X_AXIS Y_AXIS +NOTE: Doors can now be activated and deactivated with the appropriate triggers. +"inactive" set to 1 to start the door deactivated. + +if two doors touch, they are assumed to be connected and operate as +a unit. + +TOGGLE causes the door to wait in both the start and end states for +a trigger event. + +START_OPEN causes the door to move to its destination when spawned, +and operate in reverse. It is used to temporarily or permanently +close off an area when triggered (not usefull for touch or +takedamage doors). + +Key doors are allways wait -1. + +You need to have an origin brush as part of this entity. The +center of that brush will be +the point around which it is rotated. It will rotate around the Z +axis by default. You can +check either the X_AXIS or Y_AXIS box to change that. + +REVERSE will cause the door to rotate in the opposite direction. + +"flags" is how many degrees the door will be rotated. +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. +"health" if set, door must be shot open +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return) +"dmg" damage to inflict when blocked (2 default) +a "dmg" of -1 will make it only hurt non-players +"flags2" will damage the object that touches it +"strength" When set to 1, it will throw something if it gets in the way +"close_target" secondary target to fire when door closes + +"soundtype" +0) no sound +1) Big metal door, swinging +2) Big stone door, sliding +3) Big wood door, swinging +4) Normal wood door, swinging +5) Big wood door, sliding +6) Drawbridge +7) Rotating walkway +8) Big metal door, sliding +9) Pendulum swinging + + +"abslight" - to set the absolute light level + +Puzzle Pieces (use the puzzle_id value from the pieces) + puzzle_piece_1 + puzzle_piece_2 + puzzle_piece_3 + puzzle_piece_4 + no_puzzle_msg: message when player doesn't have the right pieces +*/ + +void func_door_rotating() +{ +vector vec; + + if(self.targetname=="opendraw") + { + self.wait = -1; + self.dmg=10000; + } + + self.dflags=self.flags;//don't ask + self.flags=0; + + // set the axis of rotation + if (self.spawnflags & 64) + self.movedir = '0 0 1'; + else if (self.spawnflags & 128) + self.movedir = '1 0 0'; + else + self.movedir = '0 1 0'; + + // check for clockwise rotation + if (self.spawnflags & 2) + self.movedir = self.movedir * -1; + + // CHEAT hack to get the puzzle piece flags stored in the + // same area, without re-arranging the fields so that the + // designers don't complain + self.spawnflags (-) 192; + if (self.spawnflags & 8) + self.spawnflags (+) DOOR_REMOVE_PP; + if (self.spawnflags & 16) + self.spawnflags (+) DOOR_NO_PP; + + if (self.spawnflags & 32) + self.spawnflags (+) DOOR_TOGGLE; + + self.pos1 = self.angles; + self.pos2 = self.angles + self.movedir * self.dflags; + + self.max_health = self.health; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + self.classname = "door_rotating"; + self.netname = "door"; + + if (self.abslight) + self.drawflags (+) MLS_ABSLIGHT; + + if (!self.speed) + self.speed = 100; + if (self.wait==0) + self.wait = 3; + if (!self.dmg) +// self.dmg = -1; + self.dmg = 2; + if(self.wait== -2||self.strength==1) + { + self.th_die = chunk_death; + if(self.strength==1) + self.takedamage = DAMAGE_YES; + if (!self.health) + { + if ((self.thingtype == THINGTYPE_GLASS) || (self.thingtype == THINGTYPE_CLEARGLASS)) + self.max_health = self.health = 25; + else if ((self.thingtype == THINGTYPE_GREYSTONE) || (self.thingtype == THINGTYPE_BROWNSTONE)||self.thingtype==THINGTYPE_DIRT) + self.max_health = self.health = 75; + else if (self.thingtype == THINGTYPE_WOOD) + self.max_health = self.health = 50; + else if (self.thingtype == THINGTYPE_METAL) + self.max_health = self.health = 100; + else if (self.thingtype == THINGTYPE_FLESH) + self.max_health = self.health = 30; + else + self.max_health = self.health = 25; + } + } + + door_sounds(); + +// DOOR_START_OPEN is to allow an entity to be lighted in the closed position +// but spawn in the open position + if (self.spawnflags & DOOR_START_OPEN) + { + self.angles = self.pos2; + vec = self.pos2; + self.pos2 = self.pos1; + self.pos1 = vec; + self.movedir = self.movedir * -1; + } + + self.state = STATE_BOTTOM; + + self.touch = door_touch; + if(world.spawnflags&MISSIONPACK) + self.blocked = door_blocked_mp; + else + self.blocked = door_blocked; + self.use = door_use; + + if (self.puzzle_piece_1 != string_null || + self.puzzle_piece_2 != string_null || + self.puzzle_piece_3 != string_null || + self.puzzle_piece_4 != string_null) + self.wait = -1; + +// LinkDoors can't be done until all of the doors have been spawned, so +// the sizes can be detected properly. + + self.think = LinkDoors; + self.nextthink = self.ltime + 0.1; + + if (self.cnt) + { + self.touch = SUB_Null; + self.use = door_rotate_incr; + } + + if (self.flags2) + { + self.touch = door_damage; + self.flags2=FALSE; + } +} + diff --git a/dthfire.hc b/dthfire.hc new file mode 100644 index 0000000..a545157 --- /dev/null +++ b/dthfire.hc @@ -0,0 +1,88 @@ +void trap_death_fireball_use (); +void trap_death_fireball_wait (); + +void death_fireball_touch () +{ + local float damg; + + sound (self, CHAN_WEAPON, "misc/combust.wav", 1, ATTN_NORM); + + damg = (12 + random(1,10)); + + if (other.health) + T_Damage (other, self, self.owner, damg ); + + T_RadiusDamage (self, self.owner, damg, other); + + self.origin = self.origin - 8*normalize(self.velocity); + + remove(self); +} + +void trap_death_fireball_wait () +{ + self.think = trap_death_fireball_use; + thinktime self : random(0.1, 2); +} + +void death_fireball_think () +{ + if ((vlen(self.velocity) < 50)) + { + dprint("KABLOEY!\n"); + MeteoriteFizzle(); + return; + } + + particle4(self.origin,75,random(272,288),PARTICLETYPE_FIREBALL,random(5,10)); + self.think=death_fireball_think; + thinktime self : 0.1; +} + +void trap_death_fireball_use () +{ + entity fireball; + vector vec; + + makevectors(self.angles); + vec = v_up; + vec_x += random(-0.2,0.2); + vec_y += random(-0.2,0.2); + + sound (self, CHAN_WEAPON, "raven/littorch.wav", 1, ATTN_NORM); + fireball = spawn (); + fireball.movetype = MOVETYPE_BOUNCE; + fireball.solid = SOLID_BBOX; + fireball.speed=random(600, 1000); + fireball.velocity=vec*fireball.speed; + fireball.touch = death_fireball_touch; + fireball.dmg=self.dmg; + fireball.owner = self; + fireball.angles = vectoangles (fireball.velocity); + fireball.think = death_fireball_think; + thinktime fireball : 0.1; + self.last_attack=time; + setmodel (fireball, "models/dthball.mdl"); + setsize (fireball, '0 0 0', '0 0 0'); + setorigin (fireball,self.origin); +} + + +/*QUAKED trap_death_fireball (1 0.3 0) (0 0 0) (16 16 16) +-------------------------FIELDS------------------------- +.wait = How long to wait between firings (default 0.5) +.dmg = How much damage to do with each shot (default 10) +-------------------------------------------------------- +*/ +void () trap_death_fireball = +{ + precache_sound("imp/fireball.wav"); + precache_model("models/drgnball.mdl"); + if(!self.wait) + self.wait=0.5; + if(!self.dmg) + self.dmg=10; + self.use = trap_death_fireball_wait; +}; + + diff --git a/dthhorse.hc b/dthhorse.hc new file mode 100644 index 0000000..546934c --- /dev/null +++ b/dthhorse.hc @@ -0,0 +1,970 @@ +/* + * $Header: /HexenWorld/Siege/dthhorse.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\RdrDeath\Horse\ + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\RdrDeath\Horse\Final +$origin 0 0 0 +$base base skin +$skin skin +$flags 0 + +// Horse frames +$frame Hgall1 Hgall2 Hgall3 Hgall4 Hgall5 +$frame Hgall6 Hgall7 Hgall8 Hgall9 Hgall10 +$frame Hgall11 Hgall12 + +$framevalue 0 + +// Rider Frames +$frame Rgall1 Rgall2 Rgall3 Rgall4 Rgall5 +$frame Rgall6 Rgall7 Rgall8 Rgall9 Rgall10 +$frame Rgall11 Rgall12 + +// +$frame Rsickl1 Rsickl2 Rsickl3 Rsickl4 Rsickl5 +$frame Rsickl6 Rsickl7 Rsickl8 Rsickl9 Rsickl10 +$frame Rsickl11 Rsickl12 + + + + + + + +float death_color[12] = +{ + 15, + 14, + 13, + 12, + 10, + 8, + 6, + 5, + 7, + 10, + 13, + 0 +}; + +/* 15, + 13, + 11, + 9, + 7, + 5, + 3, + 1, + 5, + 10, + 12, + 0 +*/ +float death_start[1] = +{ + $Hgall1 +}; + +float death_end[1] = +{ + $Hgall12 +}; + +float death_speed[1] = +{ + 12 +}; + +// Array to align frames +float DeathRiderFrames[4] = +{ + $Rgall1, // Animation for gallop + + $Rsickl1, // Animation for attack #1 + $Rsickl8, // Attack Frame 1 + $Rsickl9 // Attack Frame 2 +}; + +float DH_STAGE_NORMAL = 0; +float DH_STAGE_ATTACK1 = 4; +float DH_STAGE_ATTACK2 = 8; +float DH_STAGE_ATTACK3 = 16; + +void die_out () +{ + if(self.owner.cnt>0) + self.owner.cnt -= 1; + sound(self,CHAN_BODY,"death/fout.wav",1,ATTN_NORM); + remove(self); +} + +void circle_of_fire () +{ + self.angles_y+=15; + if(self.angles_y>360) + self.angles_y-=360; + + if (self.dmg >= 80) + { + self.think=die_out; + thinktime self : 4.2; + } + else + { + setorigin(self,self.o_angle-'0 0 76'); + self.dmg+=3.33; + T_RadiusDamage(self,self.owner,self.dmg/3,self.owner); + + makevectors(self.angles); + setorigin(self,self.o_angle+v_forward*100); + SpawnMummyFlame(); + + self.think=circle_of_fire; + thinktime self : 0.05; + } +} + +void go_boom() +{ + sound (newmis, CHAN_AUTO, "weapons/expsmall.wav", 1, ATTN_NORM); + BecomeExplosion(CE_FLOOR_EXPLOSION); +} + +void fire_circ_hit () +{ + self.touch=SUB_Null; + self.solid=SOLID_NOT; + self.movetype=MOVETYPE_NONE; + self.effects=EF_NODRAW; + self.angles='0 0 0'; + sound(self,CHAN_VOICE,"eidolon/flamend.wav",1,ATTN_NORM); + sound(self,CHAN_BODY,"misc/fburn_bg.wav",1,ATTN_NORM); + if(other.takedamage) + { + setorigin(self,other.origin+'0 0 100'); + self.angles_y=other.angles_y; + } + self.o_angle=self.origin; + self.ideal_yaw=self.angles_y; + + newmis=spawn(); + newmis.owner = self.owner; + traceline(self.origin,self.origin-'0 0 600',TRUE,self); + setorigin(newmis,trace_endpos); + newmis.think=go_boom; + thinktime newmis : 0; + + self.dmg=0; + self.think=circle_of_fire; + thinktime self : 0; +} + +void firecirc_fall_think() +{ + if (self.lifetime < time || vlen(self.enemy.origin - self.origin) < 40) + { + other=self.enemy; + self.think=self.touch; + thinktime self : 0; + return; + } + + HomeThink(); + self.angles=vectoangles(self.velocity); + + AdvanceFrame(0,9); + + self.think = firecirc_fall_think; + thinktime self : 0.1; +} + +void drop_fire_circ () +{ + self.cnt += 1; + self.attack_finished = time + 10; + + if(!self.enemy.flags2&FL_ALIVE) + self.enemy=find(world,classname,"player"); + + if(!self.enemy) + return; + + sound (self, CHAN_WEAPON, "death/dthfire.wav", 1, ATTN_NONE); + + Create_Missile(self,self.origin + v_forward*4 + v_right * 10 + v_up * 36, + self.movechain.enemy.origin+self.movechain.enemy.view_ofs + self.movechain.size+'0 0 30',"models/fireball.mdl","circfire",0,700,fire_circ_hit); + + newmis.enemy=newmis.lockentity=self.enemy; + newmis.movetype=MOVETYPE_FLYMISSILE; + + newmis.speed=700; //Speed + newmis.turn_time=0.5; //Lower the number, tighter the turn + + newmis.lifetime = time + 3; + newmis.think=firecirc_fall_think; + newmis.owner = self; + thinktime newmis : 0; +} + +void bone_think(void) +{ + remove(self); +} + +void bone_touch(void) +{ + self.flags (-) FL_ONGROUND; + + if (self.classname == "b4" || self.classname == "b5") + remove(self); + + if (self.count) + remove(self); + + self.avelocity_x /= 2; + self.avelocity_y /= 2; + self.avelocity_z /= 2; + if (self.classname == "b6") + self.velocity_z /= 2; + else + self.velocity_z /= 4; + + particle4(self.origin + '0 0 10', random(20), 256+random(80, 95), PARTICLETYPE_GRAV, random(10)); + + self.think = chunk_death; + thinktime self : 0.1; + + T_Damage(other, self, self.owner, random(1,3)); +} + +void generate_bone(void) +{ + entity bone; + float chance,c2; + vector place; + + bone = spawn(); + bone.owner = self.owner; + bone.solid = SOLID_BBOX; + bone.movetype = MOVETYPE_BOUNCE; + + chance = self.enemy.angles_y + random(-50,50); + c2 = random(170,250); + place_x = c2 * cos(chance); + place_y = c2 * sin(chance); + place_z = -10; + place += self.maxs; + + bone.avelocity = randomv('-400 -400 -400', '400 400 400'); + + chance = random(); + if (chance < 0.1) // rib + { + setmodel(bone,"models/boss/bone1.mdl"); + bone.classname = "b1"; + } + else if (chance < 0.2) // femer? + { + setmodel(bone,"models/boss/bone2.mdl"); + bone.classname = "b2"; + } + else if (chance < 0.3) // skull + { + setmodel(bone,"models/boss/bone6.mdl"); + bone.classname = "b6"; + } + else if (chance < 0.6) // Small piece + { + setmodel(bone,"models/boss/bone4.mdl"); + bone.classname = "b4"; + } + else // Sharp peice + { + setmodel(bone,"models/boss/bone5.mdl"); + bone.classname = "b5"; + bone.avelocity = '0 0 0'; + } + + setsize(bone, '0 0 0', '0 0 0'); + setorigin(bone, place); + + place = self.enemy.origin - bone.origin; + place_z = 0; + place = normalize(place); + place *= random(200,280); + place_z = random(-400, -600); + bone.velocity = place; + + if (random() < 0.8) + self.count = 1; + + bone.netname="deathbone"; + bone.touch = bone_touch; + bone.think = bone_think; + thinktime bone : 5; +} + +void bones_think(void) +{ + if (time > self.monster_duration) + { + if(self.owner.cnt>0) + self.owner.cnt -= 1; + + remove(self); + return; + } + + thinktime self : 0.1; + + traceline(self.enemy.origin,self.enemy.origin + '0 0 999', 1, self.enemy); + self.maxs = trace_endpos; + traceline(self.enemy.origin,self.enemy.origin - '0 0 999', 1, self.enemy); + self.mins = trace_endpos; + + generate_bone(); + if (random() < 0.8) + generate_bone(); + if (random() < 0.5) + generate_bone(); +} + +void death_bones(void) +{ + entity dr; + + sound (self, CHAN_BODY, "death/dthlaugh.wav", 1, ATTN_NONE); + + dr = spawn(); + dr.owner = self.owner; + dr.solid = SOLID_NOT; + dr.movetype = MOVETYPE_NONE; + dr.effects = EF_NODRAW; + dr.monster_duration = time + random(4,6); + dr.enemy = self.enemy; + dr.think = bones_think; + thinktime dr : HX_FRAME_TIME; +} + +void death_missile_die(void) +{ + if(self.owner.cnt>0) + self.owner.cnt -= 1; + + CreateRedCloud (self.origin,'0 0 0',HX_FRAME_TIME); + + remove(self.trigger_field.trigger_field); + remove(self.trigger_field); + remove(self); +} + +void death_missile_touch(void) +{ + remove(self.trigger_field.trigger_field); + remove(self.trigger_field); + + if (other.classname != "player") + {//FIXME: temp effect + if(self.owner.cnt>0) + self.owner.cnt -= 1; + MultiExplode(); + return; + } + + death_bones(); + + remove(self); +} + +void death_missile_think(void) +{ +//float diff,adjust; + if(self.lifetime<=time) + { + remove(self.trigger_field.trigger_field); + remove(self.trigger_field); + remove(self); + } + else + { + thinktime self : 0.1; + + self.trigger_field.trigger_field.origin = self.trigger_field.origin; + self.trigger_field.trigger_field.angles = self.trigger_field.angles; + self.trigger_field.origin = self.wallspot; + self.trigger_field.angles = self.o_angle; + self.o_angle=self.angles; + self.wallspot=self.origin; + + HomeThink(); + + self.angles=vectoangles(self.velocity); + } +/* + if (self.lifetime < time) + { + self.th_die(); + return; + } + + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.count += 9; + if (self.count > 360) + self.count = -360; + + adjust = sin(self.count) * 20; + + self.trigger_field.trigger_field.origin = self.trigger_field.origin; + self.trigger_field.trigger_field.angles = self.trigger_field.angles; + self.trigger_field.origin = self.origin; + self.trigger_field.angles = self.angles; + ChangeYaw(); + walkmove(self.angles_y + adjust, 25, TRUE); + if (trace_ent) + { + other = trace_ent; + death_missile_touch(); + } + + diff = self.enemy.origin_z - self.origin_z + self.enemy.view_ofs_z; + if (diff > 10) + diff = 10; + else if (diff < -10) + diff = -10; + diff += adjust / 4; + movestep(0,0,diff,FALSE); +*/ +} + +void death_missile_2_touch(void) +{ + float damg; + + if(self.owner.cnt>0) + self.owner.cnt -= 1; + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + damg = random(4,8); + + T_Damage (other, self, self.owner, damg ); + + self.origin = self.origin - 8 * normalize(self.velocity) - '0 0 40'; + sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + + CreateRedSpark (self.origin); + + remove(self); + +} + +void death_missile_2_think (void) +{ + if (self.lifetime < time || !self.enemy.flags2 & FL_ALIVE) + { + if(self.owner.cnt>0) + self.owner.cnt -= 1; + sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + CreateRedSpark (self.origin); + remove(self); + } + else + { + HomeThink(); + self.angles = vectoangles(self.velocity); + self.think=famine_missile_think; + thinktime self : 0.1; + } +} + +void death_missile_2(float dir) +{ + entity newmis; + vector diff; + + if(!self.enemy.flags2&FL_ALIVE) + self.enemy=find(world,classname,"player"); + + if(!self.enemy) + return; + + self.cnt += 1; + self.attack_finished = time + 7; + + newmis = spawn (); + newmis.enemy=newmis.lockentity=self.enemy; + newmis.owner = self; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_BBOX; + + setmodel (newmis, "models/famshot.mdl"); + setsize (newmis, '0 0 0', '0 0 0'); + setorigin (newmis, self.origin + '0 0 120'); + + newmis.angles = self.angles; + + makevectors(self.angles); + +// if (infront(self.enemy)) + diff = v_forward * 16; +// else +// diff = v_forward * -16; + + newmis.velocity = normalize(diff); + newmis.angles = vectoangles(newmis.velocity); + + if (dir == 0) + newmis.angles_y -= 25; + else if (dir == 2) + newmis.angles_y += 25; + makevectors (newmis.angles); + + + newmis.velocity = normalize(v_forward); + + if (dir ==1) + newmis.speed=800; //Speed + else + newmis.speed=700; //Speed + + newmis.classname = "deathmissile"; + newmis.angles = vectoangles(newmis.velocity); + + newmis.veer=FALSE; //No random wandering + newmis.turn_time=2.25; //Lower the number, tighter the turn + newmis.lifetime = time + 3; + newmis.think=famine_missile_think; + thinktime newmis : 0.1; + + newmis.touch = famine_missile_touch; +} + +void death_missile(void) +{ + entity dm; + + + if(!self.enemy.flags2&FL_ALIVE) + self.enemy=find(world,classname,"player"); + + if(!self.enemy) + return; + + self.cnt += 1; + self.attack_finished = time + 10; + + dm = spawn(); + dm.enemy=dm.lockentity=self.enemy; + dm.solid = SOLID_BBOX; + dm.movetype = MOVETYPE_FLYMISSILE; + dm.classname = "death_missile"; +// dm.flags (+) FL_FLY; + dm.drawflags (+) DRF_TRANSLUCENT | MLS_POWERMODE; + dm.enemy = self.enemy; +// dm.yaw_speed = 8; + dm.takedamage = DAMAGE_YES; + dm.health = 10; + dm.owner = self; + dm.scale = 1.5; + setmodel(dm,"models/boss/bone3.mdl"); + setorigin(dm, self.movechain.origin+self.movechain.size); + dm.think = death_missile_think; + dm.touch = death_missile_touch; + dm.th_die = death_missile_die; + dm.lifetime = time + 5; + + dm.speed=500; + dm.veer=50; //some random wandering + dm.turn_time=2; //Lower the number, tighter the turn + + setsize(dm,'0 0 0', '0 0 0'); + thinktime dm : HX_FRAME_TIME; + + dm.trigger_field = spawn(); + dm = dm.trigger_field; + dm.classname = "death_missile"; + dm.solid = SOLID_NOT; + dm.movetype = MOVETYPE_FLYMISSILE; + dm.flags (+) FL_FLY; + dm.drawflags (+) DRF_TRANSLUCENT | MLS_POWERMODE | SCALE_TYPE_UNIFORM; + dm.enemy = self.enemy; + dm.owner = dm.trigger_field; + dm.lifetime = time + 5; + setmodel(dm,"models/boss/bone3.mdl"); + setsize(dm,'0 0 0', '0 0 0'); + setorigin(dm, self.origin); + + dm.trigger_field = spawn(); + dm = dm.trigger_field; + dm.classname = "death_missile"; + dm.solid = SOLID_NOT; + dm.movetype = MOVETYPE_FLYMISSILE; + dm.flags (+) FL_FLY; + dm.drawflags (+) DRF_TRANSLUCENT | MLS_POWERMODE | SCALE_TYPE_UNIFORM; + dm.enemy = self.enemy; + dm.owner = dm.trigger_field; + dm.scale = .5; + dm.lifetime = time + 5; + setmodel(dm,"models/boss/bone3.mdl"); + setsize(dm,'0 0 0', '0 0 0'); + setorigin(dm, self.origin); + + sound (dm, CHAN_BODY, "ambience/moan1.wav", 1, ATTN_NORM); +} + +void create_deathrider(entity horse) +{ + entity rider; + + rider = spawn(); + + rider.monsterclass = CLASS_BOSS; + rider.solid = SOLID_NOT; + rider.movetype = MOVETYPE_NONE; + rider.origin = horse.origin; + rider.angles = self.angles; + + setmodel (rider, "models/boss/dthrider.mdl"); + rider.skin = 0; + + horse.movechain = rider; + self.cnt = 0; + + rider.flags (+) FL_MOVECHAIN_ANGLE; +} + +void ghost_tint () +{ + if(self.cnt<12) + { + if(!self.cnt) + { + self.touch=SUB_Null; + self.effects=EF_NODRAW; + } + self.enemy.colormap = self.enemy.movechain.colormap = 2*16+ + death_color[self.cnt]; + self.cnt+=1; + thinktime self : 0.05; + } + else + { + self.enemy.colormap = self.enemy.movechain.colormap = 0; + remove(self); + } +} + +void ghost_touch () +{ + if(other.classname!="rider_death"||self.lifespan>time) + return; + else + { + if(!self.owner.flags2&FL_ALIVE) + self.owner.enemy=other; + sound(self.enemy,CHAN_VOICE,"death/victory.wav",1,ATTN_NONE); + self.think=ghost_tint; + thinktime self : 0; + } +} + +void ghost_think () +{ + if(self.scale<=2.4) + self.scale+=0.1; + if(self.speed<333) + self.speed+=7; + HomeThink(); + self.flags(-)FL_ONGROUND; + self.angles=vectoangles(self.velocity); + thinktime self : 0.1; +} + +void spawn_ghost (entity attacker) +{ +float r; + newmis=spawn(); + newmis.movetype=MOVETYPE_NOCLIP; + newmis.solid=SOLID_TRIGGER; + newmis.classname=newmis.netname="Booberry"; + newmis.owner=self; + + newmis.drawflags(+)MLS_POWERMODE|DRF_TRANSLUCENT; + newmis.scale=0.5; + + newmis.enemy=newmis.lockentity=attacker; + self.enemy=newmis; + newmis.flags2(+)FL_ALIVE; + newmis.veer=100; + newmis.speed=100; + newmis.lifespan=time+7; + newmis.turn_time=2; + newmis.hoverz=TRUE; + newmis.touch=ghost_touch; + newmis.think=ghost_think; + + makevectors(self.angles); + newmis.velocity=v_forward*150+v_up*30; + newmis.angles=vectoangles(newmis.velocity); + + newmis.think=ghost_think; + thinktime newmis : 1; + + setmodel(newmis,"models/booberry.mdl"); + setsize(newmis,'-8 -8 -8','8 8 8'); + newmis.hull=HULL_POINT; + setorigin(newmis,(self.absmin+self.absmax)*0.5); + + r=random(); + if(r<0.33) + newmis.noise="ambience/moan1.wav"; + else if(r<0.66) + newmis.noise="ambience/moan2.wav"; + else + newmis.noise="ambience/moan3.wav"; + sound(newmis,CHAN_AUTO,newmis.noise,1,ATTN_NONE); +} + +void deathhorse_move(void) +{ + float retval, r; + + if (self.velocity) + self.velocity = self.velocity * 0.9; + + if (coop) + checkenemy(); + + if(!self.enemy.flags2&FL_ALIVE&&self.enemy!=world) + self.enemy=world; + + self.think = deathhorse_move; + thinktime self : HX_FRAME_TIME; + + retval = AdvanceFrame(death_start[self.rider_gallop_mode],death_end[self.rider_gallop_mode]); + + self.movechain.angles = self.angles; + self.movechain.origin = self.origin; + + if (!self.path_current) + { + riderpath_init(); + } + + if (self.frame == 4 || self.frame == 6 || self.frame == 8 || self.frame == 10) + { + r = random(); + + if (r < 0.2) + sound (self, CHAN_BODY, "death/clop.wav", 0.3, ATTN_NORM); + else if (r < 0.4) + sound (self, CHAN_BODY, "death/clop1.wav", 0.3, ATTN_NORM); + else if (r < 0.6) + sound (self, CHAN_BODY, "death/clop2.wav", 0.3, ATTN_NORM); + else + sound (self, CHAN_BODY, "death/clop3.wav", 0.3, ATTN_NORM); + } + + riderpath_move(self.speed); + if (retval == AF_BEGINNING) + { + retval = fabs(self.rider_y_change); + + // Force a new gallop frame in + self.frame = death_start[self.rider_gallop_mode]; + + self.monster_stage = DH_STAGE_NORMAL; + + if (self.rider_gallop_mode == 0) + { + if (!self.enemy) + { + self.enemy = find(world, classname, "player"); + while(!self.enemy.flags2&FL_ALIVE&&self.enemy!=world) + self.enemy = find(self.enemy, classname, "player"); + } + + if (self.enemy != world && random() < 0.7+skill/10&&!self.cnt) + { + r = random(); + + if (r < 0.3) + self.monster_stage = DH_STAGE_ATTACK1; + else if (r < 0.6) + self.monster_stage = DH_STAGE_ATTACK3; + else + self.monster_stage = DH_STAGE_ATTACK2; + } + } + } + + if (self.cnt && self.attack_finished < time) self.cnt = 0; + + if (self.monster_stage && self.enemy.flags2 & FL_ALIVE) + { + if (self.rider_gallop_mode == 0) + { + + if (self.monster_stage == DH_STAGE_ATTACK1) + { + self.movechain.frame = DeathRiderFrames[1] + + (self.frame - death_start[self.rider_gallop_mode]); + if (self.movechain.frame == DeathRiderFrames[2]) + { + sound (self, CHAN_WEAPON, "death/dthfire.wav", 1, ATTN_NONE); + death_missile(); + } + } + else if (self.monster_stage == DH_STAGE_ATTACK2) + { + self.movechain.frame = DeathRiderFrames[1] + + (self.frame - death_start[self.rider_gallop_mode]); + if (self.movechain.frame == 18) + sound (self, CHAN_WEAPON, "death/shot.wav", 1, ATTN_NORM); + + if (self.movechain.frame == 18 || self.movechain.frame == 20 || self.movechain.frame == 22) + death_missile_2(FALSE); + } + else if (self.monster_stage == DH_STAGE_ATTACK3) + { + self.movechain.frame = DeathRiderFrames[1] + + (self.frame - death_start[self.rider_gallop_mode]); + if (self.movechain.frame == DeathRiderFrames[2]) + drop_fire_circ(); + } + + + self.colormap = self.movechain.colormap = + death_color[self.frame - death_start[self.rider_gallop_mode]]; + if(self.colormap) + { + self.colormap+=8*16; + self.movechain.colormap+=8*16; + } + } + } + else + { + self.movechain.frame = DeathRiderFrames[self.rider_gallop_mode] + + (self.frame - death_start[self.rider_gallop_mode]); + } + + + // make sure we use the last attack frame before we go out of the mode + if (retval == AF_END) + { + self.monster_stage = DH_STAGE_NORMAL; + } + + if (fabs(death_speed[self.rider_gallop_mode] - self.speed) < 0.2) + self.speed = death_speed[self.rider_gallop_mode]; + else if (death_speed[self.rider_gallop_mode] > self.speed) + self.speed += 0.2; + else + self.speed -= 0.2; +} + + + + + + + +/*QUAKED rider_death (1 0 0) (-55 -55 -24) (55 55 100) TRIGGER_WAIT +Death rider monster. You must place rider_path entites +on the map. The rider will first proceed to the +rider_path point with a path_id of 1. +-------------------------FIELDS------------------------- +map: next map to go to when you kill the rider +target: start spot on the next map +-------------------------------------------------------- + +*/ +void rider_death(void) +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model2 ("models/boss/dthhorse.mdl"); + precache_model2 ("models/boss/dthrider.mdl"); + precache_model2 ("models/famshot.mdl"); + precache_model2 ("models/boss/bone1.mdl"); + precache_model2 ("models/boss/bone2.mdl"); + precache_model2 ("models/boss/bone3.mdl"); + precache_model2 ("models/boss/bone4.mdl"); + precache_model2 ("models/boss/bone5.mdl"); + precache_model2 ("models/boss/bone6.mdl"); + precache_model2 ("models/mumshot.mdl"); + precache_model2 ("models/booberry.mdl"); + + precache_sound2 ("mummy/mislfire.wav"); + precache_sound2 ("eidolon/flamend.wav"); + precache_sound2 ("misc/fburn_bg.wav"); + precache_sound2 ("death/fout.wav"); + + precache_sound2 ("death/dthdie.wav"); + precache_sound2 ("death/dthfire.wav"); + precache_sound2 ("death/victory.wav"); + precache_sound2 ("death/dthlaugh.wav"); + precache_sound2 ("death/clop.wav"); + precache_sound2 ("death/clop1.wav"); + precache_sound2 ("death/clop2.wav"); + precache_sound2 ("death/clop3.wav"); + precache_sound2 ("death/shot.wav"); + precache_sound2 ("ambience/moan1.wav"); + precache_sound2 ("ambience/moan2.wav"); + precache_sound2 ("ambience/moan3.wav"); + + rider_init(); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_FLY; + self.thingtype = THINGTYPE_FLESH; + self.yaw_speed = 4; + + setmodel (self, "models/boss/dthhorse.mdl"); + + self.hull = HULL_POINT; + + self.skin = 0; + self.flags (+) FL_FLY|FL_MONSTER; + self.flags2(+) FL_ALIVE; + self.monsterclass = CLASS_BOSS; + + setsize (self, '-55 -55 -24', '55 55 100'); + self.health = 3500; + self.experience_value = 1000; + + self.dflags = 0; + self.rider_gallop_mode = 0; + self.speed = death_speed[self.rider_gallop_mode]; + self.rider_path_distance = 100; + self.monster_stage = DH_STAGE_NORMAL; + self.mass = 30000; + + create_deathrider(self); + + self.noise = "death/dthdie.wav"; + self.delay = 3; + + self.th_save = deathhorse_move; + self.think = multiplayer_health; + thinktime self : 1; +} + diff --git a/eidolon.hc b/eidolon.hc new file mode 100644 index 0000000..1823744 --- /dev/null +++ b/eidolon.hc @@ -0,0 +1,1303 @@ +/* +============================================================================== + +Q:\art\models\monsters\SerpentR\final\big\bigeido.hc +MG +============================================================================== +*/ +/* +// For building the model +$cd Q:\art\models\monsters\SerpentR\final\big +$origin 0 0 0 +$base BASE SKIN +$skin SKIN +$skin SKIN2 +$flags 0 +$scale 2.5 +*/ +//Shared +$frame painA1 painA2 painA3 painA4 painA5 +$frame painA6 painA7 painA8 painA9 + +// +$frame spell1 spell2 spell3 spell4 spell5 +$frame spell6 spell7 spell8 spell9 spell10 +$frame spell11 spell12 spell13 spell14 spell15 +$frame spell16 spell17 spell18 spell19 spell20 + +// +$frame tranA1 tranA2 tranA3 tranA4 tranA5 +$frame tranA6 tranA7 tranA8 + +// +$frame tranB1 tranB2 tranB3 tranB4 tranB5 +$frame tranB6 tranB7 tranB8 + +// +$frame wait1 wait2 wait3 wait4 wait5 +$frame wait6 wait7 wait8 wait9 wait10 +$frame wait11 wait12 wait13 wait14 wait15 +$frame wait16 + +// +$frame walk1 walk2 walk3 walk4 walk5 +$frame walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 walk13 walk14 walk15 +$frame walk16 walk17 walk18 walk19 walk20 +$frame walk21 walk22 walk23 walk24 + +// +$frame howl1 howl2 howl3 howl4 howl5 +$frame howl6 howl7 howl8 howl9 howl10 +$frame howl11 howl12 howl13 howl14 howl15 +$frame howl16 howl17 howl18 howl19 howl20 +$frame howl21 howl22 howl23 howl24 howl25 +$frame howl26 howl27 howl28 howl29 howl30 +$frame howl31 howl32 howl33 howl34 howl35 +$frame howl36 howl37 howl38 howl39 howl40 +$frame howl41 howl42 howl43 howl44 howl45 +$frame howl46 howl47 howl48 howl49 howl50 +$frame howl51 howl52 howl53 howl54 howl55 +$frame howl56 howl57 howl58 howl59 howl60 + +$framesave x + +//SMALL +// +// +$frame death1 death2 death3 death4 death5 +$frame death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 +$frame death16 death17 death18 death19 death20 +$frame death21 death22 death23 death24 death25 +$frame death26 death27 death28 death29 death30 + +// +$frame dwait1 dwait3 dwait5 +$frame dwait7 dwait9 +$frame dwait11 dwait13 dwait15 +$frame dwait17 dwait19 +$frame dwait21 dwait23 dwait25 +$frame dwait27 dwait29 + + +// +$frame grow1 grow3 grow5 +$frame grow7 grow9 +$frame grow11 grow13 grow15 +$frame grow17 grow19 +$frame grow21 grow23 grow25 +$frame grow27 grow29 +$frame grow31 grow33 grow35 +$frame grow37 grow39 +$frame grow41 grow43 grow45 +$frame grow47 grow49 +$frame grow51 grow53 grow55 +$frame grow57 grow59 +$frame grow61 grow63 grow65 +$frame grow67 grow69 +$frame grow71 grow72 grow73 grow74 grow75 +$frame grow76 grow77 grow78 grow79 grow80 +$frame grow81 grow82 grow83 grow84 grow85 +$frame grow86 grow87 grow88 grow89 grow90 +$frame grow91 grow92 grow93 grow94 grow95 +$frame grow96 grow97 grow98 grow99 grow100 + + +$framerestore x + +//BIG +// +$frame breath1 breath2 breath3 breath4 breath5 +$frame breath6 breath7 breath8 breath9 breath10 +$frame breath11 breath12 breath13 breath14 breath15 +$frame breath16 breath17 breath18 breath19 breath20 +$frame breath21 breath22 breath23 breath24 breath25 +$frame breath26 breath27 breath28 breath29 breath30 +$frame breath31 breath32 breath33 breath34 breath35 +$frame breath36 breath37 breath38 breath39 breath40 +$frame breath41 breath42 breath43 breath44 breath45 +$frame breath46 breath47 breath48 breath49 breath50 + +// +$frame painB1 painB2 painB3 painB4 painB5 +$frame painB6 painB7 painB8 painB9 painB10 +$frame painB11 painB12 painB13 painB14 painB15 +$frame painB16 painB17 painB18 painB19 painB20 + +// +$frame power1 power2 power3 power4 power5 +$frame power6 power7 power8 power9 power10 +$frame power11 power12 power13 power14 power15 +$frame power16 power17 power18 power19 power20 + +/*========================================================*/ + +void()orb_wait; +void()eidolon_orb_pain; +void()eidolon_run; +void()eidolon_roar; +void()eidolon_ready_roar; +void()eidolon_grow; +void(entity attacker,float total_damage)eidolon_check_fake; +void()eidolon_power; +void()eidolon_face_orb; + +void orb_die() +{ + self.owner.health=4000+skill*2000; + self.th_save=eidolon_ready_roar; + self.owner.controller=world; + self.owner.goalentity=self.owner.enemy; + self.owner.think=multiplayer_health; + thinktime self.owner : 0; + sound(self,CHAN_AUTO,"eidolon/orbxpld.wav",1,ATTN_NONE); + MonsterQuake(500); + MultiExplode(); +} + +void orb_tint_flash_from_red() [++ 0 .. 35] +{ + self.colormap+=1; + if(self.colormap==143) + self.think=orb_wait; +} + +void orb_tint_flash_to_red() [++ 0 .. 35] +{ + self.colormap-=1; + if(self.colormap==128) + self.think=orb_tint_flash_from_red; +} + +void orb_pain (entity attacker,float damage) +{ + if(attacker==self.owner||self.owner.think==eidolon_grow) + { + self.health+=damage; + return; + } + if(self.pain_finished155) + self.colormap-=1; + + self.v_angle=randomv('0 0 0','360 360 360'); + makevectors(self.v_angle); + self.view_ofs=self.origin+'0 0 1'*self.absmax_z*0.6+v_forward*44; + if(self.owner.think==eidolon_grow) + { + self.proj_ofs=(self.owner.absmin+self.owner.absmax)*0.5-'0 0 64'; + self.proj_ofs_x+=random(0-self.owner.size_x,self.owner.size_x); + self.proj_ofs_y+=random(0-self.owner.size_x,self.owner.size_x); + self.proj_ofs_z+=random(0-self.owner.size_x,self.owner.size_x); + } + else + { + makevectors(self.owner.angles); + self.proj_ofs=self.owner.origin+self.owner.proj_ofs+v_forward*200+v_right*36+'0 0 100'; + } + + do_lightning (self.owner,self.weaponframe_cnt,0, 2, self.view_ofs, self.proj_ofs,0); +} + +void orb_lightning_pattern () [++ 0 .. 35] +{ + if(self.frame==0) + sound(self,CHAN_BODY,"eidolon/orbpulse.wav",1,ATTN_NONE); + if(self.cnt) + { + if(self.weaponframe_cnt<16) + self.weaponframe_cnt+=1; + else + self.weaponframe_cnt=0; + self.cnt-=1; + self.view_ofs=self.proj_ofs; +// if(random()<0.5) + self.v_angle+=randomv('15 15 15','45 45 45'); +// else +// self.v_angle-=randomv('15 15 15','45 45 45'); + makevectors(self.v_angle); + self.proj_ofs=self.origin+'0 0 1'*self.absmax_z*0.6+v_forward*54; + do_lightning (self.owner,self.weaponframe_cnt,0, random(4), self.view_ofs, self.proj_ofs,0); + } + else + { + self.think=orb_wait; + thinktime self : 0; + } +} + +void orb_lightning_pattern_init () +{ +// dprint("Orb starting lightning\n"); + self.cnt=random(40,60); + self.weaponframe_cnt=0; + self.v_angle=randomv('0 0 0','360 360 360'); + makevectors(self.v_angle); + self.view_ofs=self.origin+'0 0 1'*self.absmax_z*0.6+v_forward*54; + self.v_angle+=randomv('-45 -45 -45','45 45 45'); + makevectors(self.v_angle); + self.proj_ofs=self.origin+'0 0 1'*self.absmax_z*0.6+v_forward*54; + do_lightning (self.owner,self.weaponframe_cnt,0, random(3), self.view_ofs, self.proj_ofs,0); + self.think=orb_lightning_pattern; + thinktime self :0.05; +} + +void orb_wait () [++ 0 .. 35] +{ + self.aflag=FALSE; + if(self.frame==0) + sound(self,CHAN_BODY,"eidolon/orbpulse.wav",1,ATTN_NONE); + + self.velocity='0 0 0'; + self.colormap=0; + + if(random()<0.1) + { + self.think=orb_lightning_pattern_init; + thinktime self :0; + } +} + + +void obj_chaos_orb_find_movechain () +{ //So chaos orb moves with platform but doesn't block geometry +entity found; + found=find(world,netname,self.netname); + if(found) + { + found.movechain=self; + self.flags(+)FL_MOVECHAIN_ANGLE; + } + self.think=orb_wait; + thinktime self : 0; +} + +/*QUAKED obj_chaos_orb (1 0 0) (-100 -100 0) (100 100 200) JEAN LUC PICARD +Big round smooth thingie. +-------------------------FIELDS------------------------- +-------------------------------------------------------- +*/ +void obj_chaos_orb () +{ + if(deathmatch) + { + remove(self); + return; + } + precache_model2 ("models/boss/chaosorb.mdl"); + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_NOCLIP; + self.takedamage=DAMAGE_YES; + self.thingtype=THINGTYPE_GLASS; + + setmodel (self, "models/boss/chaosorb.mdl"); + + setsize (self, '-48 -48 0', '48 48 123'); + self.hull=HULL_POINT; + self.monsterclass=CLASS_BOSS; + self.health = self.max_health = 2000; + + self.mass = 5000; + self.cnt=50; + + self.flags2(+)FL_ALIVE; + self.dmg=200; + self.th_die=orb_die; + self.th_pain=orb_pain; + self.drawflags(+)SCALE_ORIGIN_BOTTOM|MLS_POWERMODE; + + self.think=obj_chaos_orb_find_movechain; + thinktime self : 0.1; +} + +//==================================================================== + +void() eidolon_walk; +void()eidolon_wait; +float eidolon_check_attack() +{ +vector spot1, spot2; +entity targ; + + if(self.movetype) + return FALSE; + + if(self.goalentity==self.controller) + return FALSE; + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.proj_ofs; + spot2 = (targ.absmin+targ.absmax)*0.5; + + traceline (spot1, spot2, FALSE, self); + + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, FALSE, trace_ent); + + if (trace_ent != targ) + if(trace_ent.health>200||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + return FALSE;//Don't have a clear shot, and don't want to shoot obstruction + + enemy_range=vlen(self.enemy.origin-self.origin); + if (enemy_range < 200&&self.scale>1) + { + self.th_melee(); + return TRUE; + } + +// missile attack + if (time < self.attack_finished) + return FALSE; + + if(random()<0.3 - skill/10&&self.controller.flags2&FL_ALIVE) + return FALSE; + + self.th_missile (); + SUB_AttackFinished (random(0,2)); + return TRUE; +} + +void check_use_model (string whichmodel) +{ + if(self.model!=whichmodel) + setmodel(self,whichmodel); + + if(!self.flags2&FL_SMALL) + setsize(self,'-54 -54 0', '54 54 666'); + else + setsize(self,'-16 -16 0', '16 16 200'); + self.hull=HULL_POINT; +} + +float eidolon_riderpath_move(float move_speed) +{ +entity next_path; +float distance;//, altitude, temp; +vector displace; + + if(self.movetype==MOVETYPE_NOCLIP) + self.velocity='0 0 0'; + + next_path=riderpath_findbest(self.path_last); + distance = vhlen(self.origin - self.path_current.origin); + if (distance < self.rider_path_distance) + { + if(next_path==world) //Already on closest path + return FALSE; + else if(self.turn_time$howl5 && self.frame<$howl55 &&random()<0.3) + self.frame+=random(-4,4); + self.angles_y+=random(-11,9); + if(self.scale>2.45) + self.scale=2.3; + else if(self.scale>1&&self.scale<=2.45) + self.scale+=random(-0.1,0.05); + if(self.abslight>2) + self.abslight=1.7; + else if(self.abslight>0.3&&self.abslight<=2) + self.abslight+=random(-0.05,0.05); + if(self.lifetime$howl13) + eidolon_spawn_lightning(); + if(self.frame==$howl60) + { + self.movetype = MOVETYPE_NONE; + self.th_pain = eidolon_check_fake; + self.attack_finished=time+3; + self.think=eidolon_guarding; + } +} + +void eidolon_ready_roar() +{ +// check_use_model("models/boss/bigeido.mdl"); + sound(self,CHAN_VOICE,"eidolon/roar.wav",1,ATTN_NONE); + self.attack_finished=time+1.5; + self.frame=$howl1; + self.think=eidolon_roar; + thinktime self : 0; +} + +void eidolon_grow () [++ $grow1 .. $grow100] +{ +//FIXME: If player too close, push away +entity found; + if(self.frame<$grow71) + thinktime self : 0.1; +// check_use_model("models/boss/bigeido.mdl"); + if(self.scale<2.5) + self.scale+=0.02; + setsize (self, '-16 -16 0'*1.3333333*self.scale, '16 16 200'*1.3333333*self.scale); + self.mass=2000*1.34*self.scale; + self.hull=HULL_POINT; + self.health=self.max_health; + found=findradius(self.origin,self.size_x+25); + while(found) + { + if(found!=self&&found.solid&&found.movetype&&found.health&&found.flags2&FL_ALIVE) + { + found.velocity=normalize(found.origin-self.origin)*100; + found.velocity_z+=100; + found.flags(-)FL_ONGROUND; + T_Damage(found,self,self,3); + } + found=found.chain; + } + if(cycle_wrapped) + { + self.rider_path_distance=64; + self.weapon=0; + self.health=10000; + self.experience_value=100000; + self.drawflags(-)MLS_POWERMODE; + self.flags2(-)FL_SMALL; + self.controller.think=orb_wait; + thinktime self.controller : 0; + self.proj_ofs=self.view_ofs='0 0 200'; + check_use_model("models/boss/bigeido.mdl"); + self.frame=$howl1; + self.think=eidolon_ready_roar; + thinktime self : 1; + } +} + +void eidolon_ready_grow () [++ $dwait1 .. $dwait29] +{ + thinktime self : 0.1; + if(self.frame==$dwait29 &&self.lifetime2) + lightstylestatic(self.lockentity.style,lightval - 1); +// else if(self.frame==$dwait29 &&lineofsight(self,self.enemy)) + else if(self.frame==$dwait29) + if(infront_of_ent(self,self.enemy)) + if(infront_of_ent(self.controller,self.enemy)) + if(vlen(self.enemy.origin-self.origin)<1500) + { + self.velocity='0 0 0'; + self.movetype=MOVETYPE_NOCLIP; + self.flags(+)FL_FLY; + MonsterQuake(500); + SUB_UseTargets(); + self.target=""; + self.lifetime=time+2; + self.think=eidolon_ready_grow; + } + self.health=self.max_health; + self.lockentity.lightvalue1=lightval; +} + +void eidolon_fake_die () [++ $death1 .. $death30] +{ +// check_use_model("models/boss/smaleido.mdl"); + self.health=self.max_health; + if(self.frame==$death30) + if(self.lockentity!=world) + { + self.lockentity.wait=100; + self.lockentity.dmg=0; + self.think=eidolon_darken_sky; + } + else + self.think=eidolon_run; +} + +void eidolon_orb_pain () [++ $painB1 .. $painB20] +{ + if(self.frame==$painB1) + { +// check_use_model("models/boss/bigeido.mdl"); + if(self.controller.think==orb_lightning_recharge) + { + self.controller.think=orb_wait; + thinktime self.controller : 0; + } + } + if(self.frame==$painB20) + { + self.weapon=0; + self.goalentity=self.enemy; + self.colormap=0; + self.level=FALSE; + self.think=eidolon_run; + } +} + +void()eidolon_face_orb; +void eidolon_pain () [++ $painA1 .. $painA9] +{ +// if(self.frame==$painA1) +// check_use_model("models/boss/smaleido.mdl"); + if(self.frame==$painA9) + { + if(self.weapon>=1000&&self.controller.flags2&FL_ALIVE) + { + self.weapon=0; + self.think=eidolon_face_orb; + } + else + self.think=eidolon_run; + } +} + +void eidolon_check_fake (entity attacker,float total_damage) +{ +float pain_chance; + if(self.controller.flags2&FL_ALIVE||self.scale<1) + {//orb alive or still small + self.dmg+=self.max_health-self.health; + self.health=self.max_health; + if(self.scale>1) + { + pain_chance=0.1; + self.weapon+=total_damage; + } + else + { + pain_chance=0.6; + self.weapon=0; + } + } + else + {//Big and orb dead + pain_chance=0.2; + self.dmg=0; + } + pain_chance-=self.torncount*0.02; + if(self.movetype!=MOVETYPE_NONE) + return; + + if(self.pain_finished>time) + return; + + self.pain_finished=time+3+skill; + + if(self.dmg>=2000&&self.scale<1) + { + self.th_pain=SUB_Null; +// if(attacker.classname=="player") +// AwardExperience(attacker,self,self.experience_value); + sound(self,CHAN_VOICE,"eidolon/fakedie.wav",1,ATTN_NONE); + self.goalentity=self.enemy; + self.think=eidolon_fake_die; + } + else if(random()=1000) + { + self.goalentity=self.enemy; + sound(self,CHAN_VOICE,"eidolon/pain.wav",1,ATTN_NONE); + if(self.level) + self.think=eidolon_orb_pain; + else + self.think=eidolon_pain; + } + else + return; + thinktime self : 0; +} + +void eidolon_fireball (void) +{ +entity missile; + + self.last_attack=time; + self.cnt+=1; + if(self.cnt==2) + { + self.attack_finished=time+7; + self.cnt=0; + } + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + + missile.classname = "eidolon fireball"; + + // set missile speed + makevectors (self.angles); + missile.enemy=self.enemy; + + setmodel (missile, "models/eidoball.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + v_forward*128 + self.proj_ofs+v_right*24-v_up*12); + + missile.wallspot=normalize((self.enemy.absmin+self.enemy.absmax)*0.5-missile.origin); + missile.movedir=v_forward; + missile.movedir_z=missile.wallspot_z; + missile.speed=1000; + missile.velocity = missile.movedir*missile.speed; + + missile.touch = pmissile2_touch; + missile.angles = vectoangles(missile.velocity); + + sound(self,CHAN_AUTO,"eidolon/fireball.wav",1,ATTN_NONE); + + + thinktime missile : 0.15; + missile.think = pmissile2_puff; + missile.lifetime = time + 2; + missile.drawflags(+)MLS_ABSLIGHT; + missile.abslight=0.5; +// missile.effects=EF_BRIGHTLIGHT; + missile.scale=2; +//Homing stuff------------------- + missile.veer=FALSE; //No random wandering + missile.turn_time=2;//Lower the number, tighter the turn + missile.ideal_yaw=TRUE;//Only track things in front +//End homing stuff------------------- +} + +void flame_stream_touch () +{ + if(other.classname=="flamestream") + return; + self.effects(+)EF_MUZZLEFLASH; + if(other.takedamage) + T_Damage(other,self,self.owner,self.dmg); + else + T_RadiusDamage(self,self.owner,self.dmg*2,self.owner); + if(self.frame<24) + self.frame=24; +} + +void eidolon_power () [++ $power1 .. $power20] +{ +// check_use_model("models/boss/bigeido.mdl"); + if(self.frame==$power20) + { + self.colormap=0; + self.level=FALSE; + self.controller.think=orb_wait; + self.goalentity=self.enemy; + self.think=eidolon_run; + thinktime self : 0; + } + if(self.frame==$power8) + { + self.controller.think=orb_lightning_recharge; + thinktime self.controller : 0; + } + if(self.frame>=$power5 && self.frame<=$power15) + { + if(self.frame==$power10) + thinktime self : 2; + if(self.frame<$power10 ) + self.colormap=159 - (self.frame-$power5); + else + self.colormap=159 - ($power15 - self.frame); + } +} + +void eidolon_face_orb () [++ $walk1 .. $walk16] +{ +// check_use_model("models/boss/smaleido.mdl"); + self.ideal_yaw = vectoyaw(self.controller.origin - self.origin); + ChangeYaw(); + if(self.angles_y>self.ideal_yaw - 10&&self.angles_y=$breath25 &&self.frame<=$breath41) + { + makevectors(self.angles); + if(!self.aflag) + { +// sound(self,CHAN_BODY,"misc/combust.wav",1,ATTN_NONE); +// bprint("Flame start\n"); + sound(self,CHAN_BODY,"eidolon/flamstrt.wav",1,ATTN_NONE); + self.aflag=TRUE; + } + + if(self.t_width0.85) + { + newmis.movedir_y=newmis.wallspot_y; + newmis.movedir_x=newmis.wallspot_x; + } + + newmis.speed=300+random(50); + newmis.velocity=newmis.movedir*newmis.speed; + setmodel(newmis,"models/eidoflam.spr"); + newmis.think=fire_anim; + thinktime newmis : 0; + + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,newmis.o_angle); + self.attack_finished+=1; + } + if(self.frame==$breath50) + { + sound(self,CHAN_VOICE,"eidolon/flamend.wav",1,ATTN_NONE); + self.aflag=FALSE; + self.attack_finished=time+10; + self.think=eidolon_guarding; + } + + if(self.frame>$breath24 && self.frame<$breath41) + { + if(!self.frags) + { + self.frame-=1; + self.frags=TRUE; + } + else + self.frags=FALSE; + thinktime self : 0.025; + } +} + +void eidolon_fireballs () [++ $breath1 .. $breath50] +{ +// check_use_model("models/boss/bigeido.mdl"); + ai_face(); + if(self.frame==$breath36) + eidolon_fireball(); + if(random()<(0.1+skill/10)&&self.frame>$breath24 && self.frame<$breath41) + eidolon_fireball(); + if(self.frame==$breath50) + { + self.attack_finished=time+3; + self.think=eidolon_guarding; + } +} + +void EidoPoly () +{ +vector forward_dir; +float dot; + makevectors(self.angles); + newmis=spawn(); + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.solid=SOLID_BBOX; + newmis.owner=self; + newmis.touch=poly_touch; + + newmis.speed=700; + forward_dir=v_forward; + newmis.o_angle=self.origin+self.proj_ofs+forward_dir*220+v_right*36; + newmis.wallspot=normalize(self.enemy.origin-newmis.o_angle); + newmis.movedir=forward_dir; + newmis.movedir_z=newmis.wallspot_z*1.7; + newmis.wallspot_z=0; + makevectors(newmis.wallspot); + dot=forward_dir*v_forward; + if(dot>0.85) + { + newmis.movedir_y=newmis.wallspot_y; + newmis.movedir_x=newmis.wallspot_x; + } + newmis.velocity=newmis.movedir*newmis.speed+v_right*random(-100,100); + + newmis.drawflags=MLS_POWERMODE; + + sound(newmis,CHAN_BODY,"necro/mmfire.wav",1,ATTN_NORM); + newmis.think=polymorph_anim; + thinktime newmis : 0; + newmis.scale=2; + setmodel(newmis,"models/polymrph.spr"); + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,newmis.o_angle); +} + +void eidolon_spell () [++ $spell1 .. $spell20] +{ +// check_use_model("models/boss/smaleido.mdl"); + ai_face(); + if((random()<(0.2+skill/10)&&self.frame>=$spell8 &&self.frame<=$spell16)||self.frame==$spell10) + { + makevectors(self.angles); + self.movedir=normalize((self.enemy.absmax+self.enemy.absmin)*0.5-(self.origin+self.proj_ofs+v_forward*64)); + self.v_angle=v_forward; + self.v_angle_z=self.movedir_z; + if(self.veer) + EidoPoly(); + else + FireMagicMissile(0); + } + if(self.frame==$spell20) + { + self.veer=FALSE; + self.attack_finished=time+2; + self.think=eidolon_guarding; + } +} + +void eidolon_fire () +{ +float enemy_dist; +//NOTE: Use special pain- if hit him in the mouth as he's +// about to use fireball or flames- hurts bad + if(self.scale>1) + if(random()<0.1) + if(random()<0.1) + { + self.veer=TRUE; + eidolon_spell(); + return; + } + enemy_dist=vlen(self.enemy.origin-self.origin); + if(self.scale==0.75) + { + if(range(self.enemy)<=RANGE_MELEE) + UseBlast(); + self.artifact_active(+)ART_TOMEOFPOWER; + eidolon_spell(); + } + else if(enemy_dist>128&&enemy_dist<424) + self.think=eidolon_flames; + else if(random()<0.2) + self.think=eidolon_ready_roar; + else + { + enemy_vis=visible(self.enemy); + enemy_infront=infront(self.enemy); + if(enemy_vis&&enemy_infront) + self.think=eidolon_fireballs; + else + self.cnt=FALSE; + } +} + +void eidolon_find_lightning () +{ +entity found; + found=find(world,classname,"light_thunderstorm"); + if(found) + self.lockentity=found; +} + +void eidolon_find_orb () +{ +entity found; + found=find(world,classname,"obj_chaos_orb"); + if(found) + { + found.owner=self; + self.controller=found; + } +} + +void eidolon_walk () [++ $walk1 .. $walk24] +{ +// check_use_model("models/boss/smaleido.mdl"); + if(self.scale>1&&(self.frame==$walk2 ||self.frame==$walk14)) + sound(self,CHAN_BODY,"eidolon/stomp.wav",1,ATTN_NONE); + if(!self.lockentity) + eidolon_find_lightning(); + if(!self.controller) + eidolon_find_orb(); + ai_walk(self.speed*self.scale); +} + +void eidolon_run () [++ $walk1 .. $walk24] +{ +// dprint("Chasing\n"); +// check_use_model("models/boss/smaleido.mdl"); + + if(self.scale>1&&(self.frame==$walk2 ||self.frame==$walk14)) + sound(self,CHAN_BODY,"eidolon/stomp.wav",1,ATTN_NONE); + + if(self.enemy!=world&&!self.enemy.flags2&FL_ALIVE) + { + self.think=eidolon_ready_roar; + self.enemy=world; + } + else if(self.enemy==world) + self.think=eidolon_wait; + else + ai_run(self.speed*self.scale); +} + +void eidolon_guarding () [++ $wait1 .. $wait16] +{ +// check_use_model("models/boss/smaleido.mdl"); + +// dprint("Guarding\n"); + ai_face(); + if(self.enemy!=world&&!self.enemy.flags2&FL_ALIVE) + { + self.think=eidolon_ready_roar; + self.enemy=world; + } + else if(self.enemy==world) + self.think=eidolon_wait; + else + ai_run(self.speed*self.scale); +} + +void eidolon_wait () [++ $wait1 .. $wait16] +{ +// dprint("Waiting\n"); +// check_use_model("models/boss/smaleido.mdl"); + if(!self.lockentity) + eidolon_find_lightning(); + if(!self.controller) + eidolon_find_orb(); + + ai_stand(); +} + +void multiplayer_health () +{ +entity lastent; +float num_players; + if(coop) + { + lastent=nextent(world); + num_players=0; + while(lastent) + { + if(lastent.flags&FL_CLIENT) + num_players+=1; + lastent=find(lastent,classname,"player"); + } + if(num_players>4) + num_players=4; + self.max_health+=1000*num_players; + self.health=self.max_health; + self.torncount=num_players - 1; + } + if(self.th_save!=SUB_Null) + self.th_save(); +} + +/*QUAKED monster_eidolon (1 0 0) (-100 -100 0) (100 100 666) CUTE CUDDLY +The big bad ugly boss guy + +-------------------------FIELDS------------------------- +-------------------------------------------------------- + +*/ +void monster_eidolon(void) +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model2 ("models/boss/smaleido.mdl"); + precache_model2 ("models/boss/bigeido.mdl"); + precache_model2 ("models/eidoball.mdl"); + precache_model2 ("models/eidoflam.spr"); + precache_model2 ("models/glowball.mdl"); + precache_model2 ("models/boss/shaft.mdl"); + precache_model2 ("models/boss/circle.mdl"); + precache_model2 ("models/boss/star.mdl"); + + precache_sound2 ("eidolon/roar.wav"); + precache_sound2 ("eidolon/pain.wav"); //Hurt + precache_sound2 ("eidolon/death.wav"); //Dies- long and agonizing + precache_sound2 ("eidolon/fakedie.wav");//1st death- fake + precache_sound2 ("eidolon/spell.wav"); //Spell attack (tracking globes) + precache_sound2 ("eidolon/stomp.wav"); //Hot-steppin' + precache_sound2 ("eidolon/fireball.wav"); //Launching Nasty fireballs + precache_sound2 ("eidolon/flamstrt.wav"); // + precache_sound2 ("eidolon/flambrth.wav"); // + precache_sound2 ("eidolon/flamend.wav"); // + precache_sound2 ("eidolon/growl.wav"); // + precache_sound2 ("eidolon/chrgstrt.wav"); //Orb starts recharging Eido + precache_sound2 ("eidolon/orbhurt.wav"); //Orb gets hit + precache_sound2 ("eidolon/orbxpld.wav"); //Orb gets destroyed + precache_sound2 ("eidolon/orbpulse.wav"); //Orb pulsating + precache_sound2 ("famine/flashdie.wav"); + + total_monsters += 1; + + self.speed=10.5; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.takedamage=DAMAGE_YES; + self.monsterclass=CLASS_FINAL_BOSS; + self.flags2(+)FL_ALIVE|FL_MONSTER|FL_SMALL; + self.thingtype=THINGTYPE_FLESH; + + setmodel (self, "models/boss/smaleido.mdl"); + self.skin = 0; + + setsize (self, '-32 -32 0', '32 32 150'); + self.hull=HULL_GOLEM; + self.health = self.max_health=3000+skill*1000; + + self.yaw_speed = 10; + self.mass = 2000; + + self.rider_path_distance=30; + + self.proj_ofs=self.view_ofs='0 0 100'; + self.experience_value = 10000; + + self.th_stand = eidolon_wait; + self.th_jump = eidolon_ready_roar; + self.th_walk = eidolon_walk; + self.th_run = eidolon_run; + self.th_die = eidolon_die; + self.th_melee = eidolon_flames; + self.th_pain = eidolon_check_fake; + self.th_missile = eidolon_fire; + + self.scale = 0.75; + self.drawflags (+) SCALE_ORIGIN_BOTTOM; + self.touch=SUB_Null; + + self.th_save=walkmonster_start; + self.think=multiplayer_health; + thinktime self : 2; +} + diff --git a/enforcer.hc b/enforcer.hc new file mode 100644 index 0000000..c1f2c94 --- /dev/null +++ b/enforcer.hc @@ -0,0 +1,358 @@ +/* + * $Header: /HexenWorld/Siege/Enforcer.hc 4 5/25/98 1:38p Mgummelt $ + */ +/* +============================================================================== + +SOLDIER / PLAYER + +============================================================================== +*/ + +$cd id1/models/enforcer +$origin 0 -6 24 +$base base +$skin skin + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 walk13 walk14 walk15 walk16 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 + +$frame attack1 attack2 attack3 attack4 attack5 attack6 +$frame attack7 attack8 attack9 attack10 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 +$frame death9 death10 death11 death12 death13 death14 + +$frame fdeath1 fdeath2 fdeath3 fdeath4 fdeath5 fdeath6 fdeath7 fdeath8 +$frame fdeath9 fdeath10 fdeath11 + +$frame paina1 paina2 paina3 paina4 + +$frame painb1 painb2 painb3 painb4 painb5 + +$frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8 + +$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8 +$frame paind9 paind10 paind11 paind12 paind13 paind14 paind15 paind16 +$frame paind17 paind18 paind19 + + +void() Laser_Touch = +{ + local vector org; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC); + org = self.origin - 8*normalize(self.velocity); + + if (other.health) + { + SpawnBlood (org, self.velocity*0.2, 15); + T_Damage (other, self, self.owner, 15); + } + else + { + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_GUNSHOT); + WriteByte (MSG_BROADCAST, 1); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + } + + remove(self); +}; + +void(vector org, vector vec) LaunchLaser = +{ + local vector vec; + + if (self.classname == "monster_enforcer") + sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM); + + vec = normalize(vec); + + newmis = spawn(); + newmis.owner = self; + newmis.movetype = MOVETYPE_FLY; + newmis.solid = SOLID_BBOX; + newmis.effects = EF_DIMLIGHT; + + setmodel (newmis, "progs/laser.mdl"); + setsize (newmis, '0 0 0', '0 0 0'); + + setorigin (newmis, org); + + newmis.velocity = vec * 600; + newmis.angles = vectoangles(newmis.velocity); + + newmis.nextthink = time + 5; + newmis.think = SUB_Remove; + newmis.touch = Laser_Touch; +}; + + + +void() enforcer_fire = +{ + local vector org; + + self.effects = self.effects | EF_MUZZLEFLASH; + makevectors (self.angles); + + org = self.origin + v_forward * 30 + v_right * 8.5 + '0 0 16'; + + LaunchLaser(org, self.enemy.origin - self.origin); +}; + +//============================================================================ + +void() enf_stand1 =[ $stand1, enf_stand2 ] {ai_stand();}; +void() enf_stand2 =[ $stand2, enf_stand3 ] {ai_stand();}; +void() enf_stand3 =[ $stand3, enf_stand4 ] {ai_stand();}; +void() enf_stand4 =[ $stand4, enf_stand5 ] {ai_stand();}; +void() enf_stand5 =[ $stand5, enf_stand6 ] {ai_stand();}; +void() enf_stand6 =[ $stand6, enf_stand7 ] {ai_stand();}; +void() enf_stand7 =[ $stand7, enf_stand1 ] {ai_stand();}; + +void() enf_walk1 =[ $walk1 , enf_walk2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE); +ai_walk(2);}; +void() enf_walk2 =[ $walk2 , enf_walk3 ] {ai_walk(4);}; +void() enf_walk3 =[ $walk3 , enf_walk4 ] {ai_walk(4);}; +void() enf_walk4 =[ $walk4 , enf_walk5 ] {ai_walk(3);}; +void() enf_walk5 =[ $walk5 , enf_walk6 ] {ai_walk(1);}; +void() enf_walk6 =[ $walk6 , enf_walk7 ] {ai_walk(2);}; +void() enf_walk7 =[ $walk7 , enf_walk8 ] {ai_walk(2);}; +void() enf_walk8 =[ $walk8 , enf_walk9 ] {ai_walk(1);}; +void() enf_walk9 =[ $walk9 , enf_walk10 ] {ai_walk(2);}; +void() enf_walk10 =[ $walk10, enf_walk11 ] {ai_walk(4);}; +void() enf_walk11 =[ $walk11, enf_walk12 ] {ai_walk(4);}; +void() enf_walk12 =[ $walk12, enf_walk13 ] {ai_walk(1);}; +void() enf_walk13 =[ $walk13, enf_walk14 ] {ai_walk(2);}; +void() enf_walk14 =[ $walk14, enf_walk15 ] {ai_walk(3);}; +void() enf_walk15 =[ $walk15, enf_walk16 ] {ai_walk(4);}; +void() enf_walk16 =[ $walk16, enf_walk1 ] {ai_walk(2);}; + +void() enf_run1 =[ $run1 , enf_run2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE); +ai_run(18);}; +void() enf_run2 =[ $run2 , enf_run3 ] {ai_run(14);}; +void() enf_run3 =[ $run3 , enf_run4 ] {ai_run(7);}; +void() enf_run4 =[ $run4 , enf_run5 ] {ai_run(12);}; +void() enf_run5 =[ $run5 , enf_run6 ] {ai_run(14);}; +void() enf_run6 =[ $run6 , enf_run7 ] {ai_run(14);}; +void() enf_run7 =[ $run7 , enf_run8 ] {ai_run(7);}; +void() enf_run8 =[ $run8 , enf_run1 ] {ai_run(11);}; + +void() enf_atk1 =[ $attack1, enf_atk2 ] {ai_face();}; +void() enf_atk2 =[ $attack2, enf_atk3 ] {ai_face();}; +void() enf_atk3 =[ $attack3, enf_atk4 ] {ai_face();}; +void() enf_atk4 =[ $attack4, enf_atk5 ] {ai_face();}; +void() enf_atk5 =[ $attack5, enf_atk6 ] {ai_face();}; +void() enf_atk6 =[ $attack6, enf_atk7 ] {enforcer_fire();}; +void() enf_atk7 =[ $attack7, enf_atk8 ] {ai_face();}; +void() enf_atk8 =[ $attack8, enf_atk9 ] {ai_face();}; +void() enf_atk9 =[ $attack5, enf_atk10 ] {ai_face();}; +void() enf_atk10 =[ $attack6, enf_atk11 ] {enforcer_fire();}; +void() enf_atk11 =[ $attack7, enf_atk12 ] {ai_face();}; +void() enf_atk12 =[ $attack8, enf_atk13 ] {ai_face();}; +void() enf_atk13 =[ $attack9, enf_atk14 ] {ai_face();}; +void() enf_atk14 =[ $attack10, enf_run1 ] {ai_face(); +SUB_CheckRefire (enf_atk1); +}; + +void() enf_paina1 =[ $paina1, enf_paina2 ] {}; +void() enf_paina2 =[ $paina2, enf_paina3 ] {}; +void() enf_paina3 =[ $paina3, enf_paina4 ] {}; +void() enf_paina4 =[ $paina4, enf_run1 ] {}; + +void() enf_painb1 =[ $painb1, enf_painb2 ] {}; +void() enf_painb2 =[ $painb2, enf_painb3 ] {}; +void() enf_painb3 =[ $painb3, enf_painb4 ] {}; +void() enf_painb4 =[ $painb4, enf_painb5 ] {}; +void() enf_painb5 =[ $painb5, enf_run1 ] {}; + +void() enf_painc1 =[ $painc1, enf_painc2 ] {}; +void() enf_painc2 =[ $painc2, enf_painc3 ] {}; +void() enf_painc3 =[ $painc3, enf_painc4 ] {}; +void() enf_painc4 =[ $painc4, enf_painc5 ] {}; +void() enf_painc5 =[ $painc5, enf_painc6 ] {}; +void() enf_painc6 =[ $painc6, enf_painc7 ] {}; +void() enf_painc7 =[ $painc7, enf_painc8 ] {}; +void() enf_painc8 =[ $painc8, enf_run1 ] {}; + +void() enf_paind1 =[ $paind1, enf_paind2 ] {}; +void() enf_paind2 =[ $paind2, enf_paind3 ] {}; +void() enf_paind3 =[ $paind3, enf_paind4 ] {}; +void() enf_paind4 =[ $paind4, enf_paind5 ] {ai_painforward(2);}; +void() enf_paind5 =[ $paind5, enf_paind6 ] {ai_painforward(1);}; +void() enf_paind6 =[ $paind6, enf_paind7 ] {}; +void() enf_paind7 =[ $paind7, enf_paind8 ] {}; +void() enf_paind8 =[ $paind8, enf_paind9 ] {}; +void() enf_paind9 =[ $paind9, enf_paind10 ] {}; +void() enf_paind10 =[ $paind10, enf_paind11 ] {}; +void() enf_paind11 =[ $paind11, enf_paind12 ] {ai_painforward(1);}; +void() enf_paind12 =[ $paind12, enf_paind13 ] {ai_painforward(1);}; +void() enf_paind13 =[ $paind13, enf_paind14 ] {ai_painforward(1);}; +void() enf_paind14 =[ $paind14, enf_paind15 ] {}; +void() enf_paind15 =[ $paind15, enf_paind16 ] {}; +void() enf_paind16 =[ $paind16, enf_paind17 ] {ai_pain(1);}; +void() enf_paind17 =[ $paind17, enf_paind18 ] {ai_pain(1);}; +void() enf_paind18 =[ $paind18, enf_paind19 ] {}; +void() enf_paind19 =[ $paind19, enf_run1 ] {}; + +void(entity attacker, float damage) enf_pain = +{ + local float r; + + r = random (); + if (self.pain_finished > time) + return; + + + if (r < 0.5) + sound (self, CHAN_VOICE, "enforcer/pain1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "enforcer/pain2.wav", 1, ATTN_NORM); + + if (r < 0.2) + { + self.pain_finished = time + 1; + enf_paina1 (); + } + else if (r < 0.4) + { + self.pain_finished = time + 1; + enf_painb1 (); + } + else if (r < 0.7) + { + self.pain_finished = time + 1; + enf_painc1 (); + } + else + { + self.pain_finished = time + 2; + enf_paind1 (); + } +}; + +//============================================================================ + + + + +void() enf_die1 =[ $death1, enf_die2 ] {}; +void() enf_die2 =[ $death2, enf_die3 ] {}; +void() enf_die3 =[ $death3, enf_die4 ] +{self.solid = SOLID_NOT;self.ammo_cells = 5;DropBackpack();}; +void() enf_die4 =[ $death4, enf_die5 ] {ai_forward(14);}; +void() enf_die5 =[ $death5, enf_die6 ] {ai_forward(2);}; +void() enf_die6 =[ $death6, enf_die7 ] {}; +void() enf_die7 =[ $death7, enf_die8 ] {}; +void() enf_die8 =[ $death8, enf_die9 ] {}; +void() enf_die9 =[ $death9, enf_die10 ] {ai_forward(3);}; +void() enf_die10 =[ $death10, enf_die11 ] {ai_forward(5);}; +void() enf_die11 =[ $death11, enf_die12 ] {ai_forward(5);}; +void() enf_die12 =[ $death12, enf_die13 ] {ai_forward(5);}; +void() enf_die13 =[ $death13, enf_die14 ] {}; +void() enf_die14 =[ $death14, enf_die14 ] {}; + +void() enf_fdie1 =[ $fdeath1, enf_fdie2 ] { + +}; +void() enf_fdie2 =[ $fdeath2, enf_fdie3 ] {}; +void() enf_fdie3 =[ $fdeath3, enf_fdie4 ] +{self.solid = SOLID_NOT;self.ammo_cells = 5;DropBackpack();}; +void() enf_fdie4 =[ $fdeath4, enf_fdie5 ] {}; +void() enf_fdie5 =[ $fdeath5, enf_fdie6 ] {}; +void() enf_fdie6 =[ $fdeath6, enf_fdie7 ] {}; +void() enf_fdie7 =[ $fdeath7, enf_fdie8 ] {}; +void() enf_fdie8 =[ $fdeath8, enf_fdie9 ] {}; +void() enf_fdie9 =[ $fdeath9, enf_fdie10 ] {}; +void() enf_fdie10 =[ $fdeath10, enf_fdie11 ] {}; +void() enf_fdie11 =[ $fdeath11, enf_fdie11 ] {}; + + +void() enf_die = +{ +// check for gib + if (self.health < -35) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("progs/h_mega.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib2.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + return; + } + +// regular death + sound (self, CHAN_VOICE, "enforcer/death1.wav", 1, ATTN_NORM); + if (random() > 0.5) + enf_die1 (); + else + enf_fdie1 (); +}; + + +/*QUAK-ED monster_enforcer (1 0 0) (-16 -16 -24) (16 16 40) Ambush +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() monster_enforcer = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model2 ("progs/enforcer.mdl"); + precache_model2 ("progs/h_mega.mdl"); + precache_model2 ("progs/laser.mdl"); + + precache_sound2 ("enforcer/death1.wav"); + precache_sound2 ("enforcer/enfire.wav"); + precache_sound2 ("enforcer/enfstop.wav"); + precache_sound2 ("enforcer/idle1.wav"); + precache_sound2 ("enforcer/pain1.wav"); + precache_sound2 ("enforcer/pain2.wav"); + precache_sound2 ("enforcer/sight1.wav"); + precache_sound2 ("enforcer/sight2.wav"); + precache_sound2 ("enforcer/sight3.wav"); + precache_sound2 ("enforcer/sight4.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/enforcer.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 80; + + self.th_stand = enf_stand1; + self.th_walk = enf_walk1; + self.th_run = enf_run1; + self.th_pain = enf_pain; + self.th_die = enf_die; + self.th_missile = enf_atk1; + + walkmonster_start(); +}; + diff --git a/entity.hc b/entity.hc new file mode 100644 index 0000000..ab8e0ae --- /dev/null +++ b/entity.hc @@ -0,0 +1,780 @@ + +//************************************************************************** +//** +//** entity.hc +//** +//** $Header: /HexenWorld/Siege/entity.hc 33 6/01/98 2:49a Mgummelt $ +//** +//************************************************************************** + +// SYSTEM FIELDS ----------------------------------------------------------- +// (entvars_t C structure, *** = don't modify in HexC) --------------------- + +// *** Model index in the precached list. +.float modelindex; + +// *** Origin + mins / maxs +.vector absmin, absmax; + +// Local time for entity. +.float ltime; + +.float lastruntime; // *** to allow entities to run out of sequence + +.float movetype; +.float solid; + +// *** +.vector origin; + +// *** +.vector oldorigin; + +.vector velocity; +.vector angles; +.vector avelocity; + +// Temp angle adjust from damage or recoil. +.vector punchangle; + +// Spawn function. +.string classname; + +.string model; +.float frame; +.float skin; +.float effects; +.float scale; +.float drawflags; +.float abslight; + +// Bounding box extents relative to origin. +.vector mins, maxs; + +// maxs - mins +.vector size; + +// Which clipping hull to use. +.float hull; + +.void() touch; +.void() use; +.void() think; + +// For doors or plats, called when can't push other. +.void() blocked; + +.float nextthink; +.entity groundentity; + +// Stats +.float stats_restored; + +.float frags; +.float weapon; +.string weaponmodel; +.float weaponframe; + +.float health; // HP +.float max_health; // Max HP +.float playerclass; // 0 (none), 1-6 +.float next_playerclass; // 0 (none), 1-6 +.float has_portals; // 1 if user has portals expansion +.float bluemana; // Blue mana +.float greenmana; // Green mana +.float max_mana; // Maximum amount of mana for current class / level +.float armor_amulet; // Health of amulet armor +.float armor_bracer; // Health of bracer armor +.float armor_breastplate; // Health of breastplate armor +.float armor_helmet; // Health of helmet armor +.float level; // Player level +.float intelligence; // Player INT +.float wisdom; // Player WIS +.float dexterity; // Player DEX +.float strength; // Player STR +.float experience; // Accumulated experience points + +.float ring_flight; // Health of rings 0 - 100 +.float ring_water; // +.float ring_turning; // +.float ring_regeneration; // + +.float haste_time; // When hast is depleted +.float tome_time; // When tome of power is depleted +.string puzzle_inv1; // Puzzle piece inventory... +.string puzzle_inv2; +.string puzzle_inv3; +.string puzzle_inv4; +.string puzzle_inv5; +.string puzzle_inv6; +.string puzzle_inv7; +.string puzzle_inv8; + +// Experience this entity is worth when killed or used. +.float experience_value; + +// Bit flags. +.float items; + +.float takedamage; +.entity chain; +.float deadflag; + +// Add to origin to get eye point. +.vector view_ofs; + +// Fire. +.float button0; + +// Use. +.float button1; + +// Jump. +.float button2; + +// Weapon changes, misc. +.float impulse; + +.float fixangle; + +// View / targeting angle for players. +.vector v_angle; + +// Calculated pitch angle for slopes. +.float idealpitch; + +.float idealroll; +.float hoverz; + +.string netname; + +.entity enemy; + +.float flags; +.float flags2; +.float artifact_flags; + +.float colormap; +.float team; +.float light_level; + +.float wpn_sound; + +.float targAng; +.float targPitch; +.float targDist; + +// Don't back up. +.float teleport_time; + +// Save this fraction of incoming damage. +.float armortype; + +.float armorvalue; + +// 0 = not in, 1 = feet, 2 = waist, 3 = eyes. +.float waterlevel; + +// A contents value. +.float watertype; + +// 0 = not in a friction entity, else the friction of the entity. +.float friction; + +.float ideal_yaw; +.float yaw_speed; + +//rj.entity aiment; + +// A pathentity or an enemy. also used by axeblade for it's tail +.entity goalentity; + +.float spawnflags; + +// The target of this entity. +.string target; + +.string targetname; + +// Damage is accumulated through a frame and sent as one single +// message, so the super shotgun doesn't generate huge messages. +.float dmg_take; +.float dmg_save; +.entity dmg_inflictor; + +// Who launched a missile. +.entity owner; + +// Mostly or doors, but also used for waterjump. +.vector movedir; + +// Trigger messages. +.float message; + +// Either a CD track number or a sound number. +.float soundtype; + +// Contains names of .WAVs to play. +.string noise, noise1, noise2, noise3; + +.float rings; // Which rings hero has +.float rings_active; // Shows which rings have been activated +.float rings_low; // Shows which rings are low on power + +.float artifacts; // Which artifact hero has +.float artifact_active; // Shows which artifact have been activated +.float artifact_low; // Shows which artifact is running out + +.float hasted; // % of normal speed player has been hasted + +.float inventory; // Which item is currently chosen? +//rj.float ordr_cnt; // Number of items in order + +// make sure you change references to: +// max_ammo2() DropBackpack() BackpackTouch() +// when adding or changing inventory fields +.float cnt_torch; // Count of inventory item - Torch +.float cnt_h_boost; // Count of inventory item - Health Boost +.float cnt_sh_boost; // Count of inventory item - Super Health Boost +.float cnt_mana_boost; // Count of inventory item - Mana Boost +.float cnt_teleport; // Count of inventory item - Teleport +.float cnt_tome; // Count of inventory item - Tome of Power +.float cnt_summon; // Count of inventory item - Summon +.float cnt_invisibility; // Count of inventory item - Invisibility +.float cnt_glyph; // Count of inventory item - Glyph of the Ancients +.float cnt_haste; // Count of inventory item - Haste +.float cnt_blast; // Count of inventory item - Blast Radius +.float cnt_polymorph; // Count of inventory item - Polymorph +.float cnt_flight; // Count of inventory item - Flight +.float cnt_cubeofforce; // Count of inventory item - Cube of Force +.float cnt_invincibility; // Count of inventory item - Invincibility + +.entity cameramode; + +.entity movechain; +.void() chainmoved; + +.float string_index; // Index used for global string table +.float gravity; //Gravity, duh + +.float siege_team; //ST_ATTACKER or ST_DEFENDER +// END SYSTEM FIELDS ------------------------------------------------------- + +// Flag the compiler. +void end_sys_fields; + +// World fields +.string wad; +.string map; +.float worldtype; // 0=medieval 1=metal 2=base + +.string killtarget; + +// QuakeEd fields +.float light_lev; // Not used by game, but parsed by light util +.float style; + +// Monster AI, doubled over for player +.void() th_stand; +.void() th_walk; //player_crouch_move +.void() th_run; +.void() th_missile; //player_attack +.void() th_melee; +.void(entity attacker, float damage) th_pain; +.void() th_die; +.void() th_save; // In case you need to save/restore a thinking state + +// Mad at this player before taking damage. +.entity oldenemy; + +.float speed; +.float lefty; +.float search_time; +.float attack_state; + +// Monster AI stuff +.float monster_stage; +.float monster_duration; // Stage duration +.float monster_awake; +.float monster_check; +.vector monster_last_seen; + + +// because of how physics works, certain calls to the touch +// function of other entities involving the player do not +// allow you to adjust the velocity, so you have to do it +// outside of the inner physics stuff +.vector adjust_velocity; + +.union +{ // Entity type specific stuff + struct // player stuff + { + float splash_time; // When to generate the next splash + float camera_time; // + float weaponframe_cnt; // + float attack_cnt; // Shows which attack animation can be used + float ring_regen_time; // When to add the next point of health + float ring_flight_time; // When to update ring of flight health + float ring_water_time; // When to update ring of waterbreathing health + float ring_turning_time;// When to update ring of turning health + float super_damage; // Player does this much more damage (Like Crusader with Special Ability #2) + float super_damage_low; // Flag the super damage is low + float puzzles_cheat; // Allows player past puzzle triggers + float camptime; // Amount of time player has been motionless + float crouch_time; // Next time player should run crouch subroutine + float crouch_stuck; // If set this means the player has released the crouch key in an area too small to uncrouch in + float divine_time; // Amount of time flash happens in divine intervention + float act_state; // Anim info + float raven_cnt; // Number of raven's this guys has in the world + float newclass; // If doing a quick class change + float poweredFlags; // Which weapons are available for being powered up in tomeMode 2 + float last_use_time; // when i last performed operation (inv. use, sheepify, suicide) that shouldn't rapid-fire. + float jail_time; + }; + struct + { // Fallen Angel + float fangel_SaveFrame; + float fangel_Count; + float shoot_cnt; + float shoot_time; // Time of last shot + float z_movement; + float z_duration; + float drop_time; + }; + struct + { // Fallen Angel's Spell + float spell_angle; + }; + struct + { // Hydra + float hydra_FloatTo; + float hydra_chargeTime; + }; + struct + { // Spider + float spiderType; // SPIDER_? types + float spiderActiveCount; // Tallies "activity" + float spiderGoPause; // Active/pause threshold + float spiderPauseLength; // Pause duration in frames + float spiderPauseCount; // Tallies paused frames + }; + struct + { // Scorpion + float scorpionType; // SCORPION_? types + float scorpionRest; // Resting state counter + float scorpionWalkCount; // Counts walking frames + }; + struct + { // Golem + float golemSlideCounter; + float golemBeamDelay; + float golemBeamOff1; + float golemBeamOff2; + }; + struct + { // Imp + float impType; // IMP_? types + }; + struct + { // Mummy + float parts_gone; + float mummy_state; + float mummy_state_time; + }; + struct + { // Artifacts + float artifact_respawn; // Should respawn? + float artifact_ignore_owner_time; + float artifact_ignore_time; + float artifact_name; + }; + struct + { // Rider path + float next_path_1; + float next_path_2; + float next_path_3; + float next_path_4; + float path_id; + float next_path_5; + float next_path_6; + }; + struct + { // Rider triggers + float rt_chance; + }; + struct + { // Rider data + float rider_gallop_mode; + float rider_last_y_change; + float rider_y_change; + float rider_death_speed; + float rider_path_distance; + float rider_move_adjustment; + }; + struct + { // War rider axe + float waraxe_offset; + float waraxe_horizontal; + float waraxe_track_inc; + float waraxe_track_limit; + float waraxe_max_speed; + float waraxe_max_height; + }; + struct + { // War rider's quake + float wrq_effect_id; + float wrq_radius; + float wrq_count; + }; + struct + { // Rider's beam + float beam_angle_a; + float beam_angle_b; + float beam_max_scale; + float beam_direction; + float beam_speed; + }; + struct + { // Used by smoke generator + float z_modifier; + }; + struct + { + float last_health; // Used by bell entity + }; + struct // For raven staff Ravens + { + float idealpitch; + float pitchdowntime; + float searchtime; // Amount of time bird has been searching + float next_action; // Next time to take action + float searchtime; // When search was first started + float damage_max; // Amount of damage each raven can do before it has to leave + float raven_effect_id; //effect id number + entity raven_owner; //owner field can get modified by refections + vector last_vel; // last updated velocity, tells when change needed + }; + struct + { // fish + float fish_speed; + float fish_leader_count; + }; + + struct + { // Used by particle explosion entity. + float exploderadius; + }; + + struct + { // Skull missiles from skullwizard + float scream_time; + }; + struct + { + float attack_cnt; + }; + struct + { // Pestalance's Hive + float beginframe; + }; + struct + { // Soul spheres + float sound_time; + }; + struct + { // Cube of force + float shot_cnt; // Number of shots the force cube has shot + }; + struct + { // xbow bolts + entity firstbolt; // maintain list of bolts that use same effect, so it can be removed when all bolts are gone + entity nextbolt; + + float boltnum; // when i tell effect to change, it has to know which bolt changes + float xbo_effect_id; + + vector xbo_startpos;//save where bolt is fired from; since bolts don't accelerate, + //can just send the distance they travelled instead of ending position + + float fusetime;//determine how long tomed bolts wait til exploding when they are shot + + float xbo_teleported;//bolt has just been teleported. + }; +}; + +// Once we can do unions above end_sys, have this with the field 'playerclass' +.float monsterclass; + +// FIXME: Remove the ring of spell turning and all references to this +.float turn_time; + +// Triggers / doors +.string puzzle_piece_1; +.string puzzle_piece_2; +.string puzzle_piece_3; +.string puzzle_piece_4; +.float no_puzzle_msg; + +// Puzzle Item +.string puzzle_id; + +// More rider stuff that can't be in the union +.entity path_current; + +.vector oldangles; +.string lastweapon; // Weapon model player had before changing to camera mode + +.float lifetime; +.float lifespan; + +.float walkframe; +.float wfs; // Weapon frame state + +.float attack_finished; +.float pain_finished; + +.float invisible_finished; + +.float invincible_time, invincible_sound; +.float invisible_time; +.float super_damage_time; + +// Set to time+0.2 whenever a client fires a weapon or takes damage. +// Used to alert monsters that otherwise would let the player go. +.float show_hostile; + +// Player jump flag. +.float jump_flag; + +// Player swimming sound flag. +.float swim_flag; + +// When time > air_finished, start drowning. +.float air_finished; + +// Keeps track of the number of bubbles. +.float bubble_count; + +// Keeps track of how the player died. +.string deathtype; + +// Object stuff. +.string mdl; +.vector mangle; // Angle at start + +// Only used by secret door. +.vector oldorigin; + +.float t_length, t_width; + +// Things color. +.float color; + +// Count of things (used by rain entity) +.float counter; + +// Can these be made part of a union?? +.float plaqueflg; // 0 if not using a plaque, 1 if using a plaque +.vector plaqueangle; // Angle player was facing when the plaque was touched + + +// Doors, etc. +.vector dest, dest1, dest2; +.float wait; // Time from firing to restarting +.float delay; // Time from activation to firing +.entity trigger_field; // Door's trigger entity +.string noise4; + +// Monsters. +.float pausetime; +.entity pathentity; + +// Doors. +.float aflag; +.float dmg; // Damage done by door when hit + +// Misc flag. +.float cnt; + +// What type of thing is this? +.float thingtype; + + +// Amount of time left on torch. +.float torchtime; + +// Next torch think. +.void() torchthink; + +// Amount of time left on the super health. +.float healthtime; + +// Subs +.void() think1; +.vector finaldest, finalangle; + +// For counting triggers +.float count; + +.float spawn_health; // Set to >0 to spawn instant health + +// Plats/doors/buttons +.float lip; +.float state; +.vector pos1, pos2; // Top and bottom positions +.float height; + +// Sounds +//.float waitmin, waitmax; +//.float distance; +//.float volume; + +.vector orgnl_mins, orgnl_maxs; // original bounding box + +.float veer; //Amount of veer when Veer function called (included in HomeThink Function) + //The higher the number, the more drastic the wander is. +.float homerate;//Turning rate on homing missiles, is used as the nextthink time + //so the lower the number, the tighter thr turn radius. + //From the SpiralThink function, a value of FALSE will + //stop it from randomly homing while spiraling, + //a value of TRUE will allow it to randomly Home, but + //does not effect rate of homing since it only calls + //it randomly. +.float mass; //NOTE: 1 = @18.5 pounds. + //How much they weigh- should be used in all velocity mods + //(pushing, impact, throwing). Used as a divider, so + //the higher the number, the higher the mass, the less + //distance it will go. Make sure it's >0 + //Buttons and pressure plates can use this too so that + //if a light object is placed on it, it won't activate + //(but it should be cumulative so that you can stack several + //light objects to increase mass and activate it) + //Also, a light player (featherfall?) could get around + //certain traps? +.float onfire; //A value that, when FALSE means the object is not on + //fire. A greater than zero value indicates how fast + //the thing is burning. The higher the number, the higher + //the damage and the more flames. + +.vector o_angle;//Just to remember an old angle or vector + +//Player +.float bloodloss;//For the Bleed() function which will remove health + //and add graphic. Set to 666 for beheading death. +.float oldweapon;//For remembering your last weapon, has many uses + +//Monsters (and some projectiles) +.entity controller; //What is the owner of this thing, this allows + //it to touch it's owner if you set the owner + //to self. + +.float init_modelindex;//initial model index, so you can switch away and back +.string init_model; + +//Player Only th_*** +.void() th_swim; +.void() th_jump; +.void() th_fly; +.void() th_die1; +.void() th_die2; +.void() th_goredeath; + +.void() th_possum; //Monster playing dead +.void() th_possum_up; //Monster getting up from playing dead + +.float last_attack; //Used for weapons that go into rest mode after + //a while +.entity shield; +.float frozen; //Can't be a flag, is a counter +.float oldskin; +.void() oldthink; +.void() th_weapon; +.float decap; //To know if was beheaded, not a flag, set to 2 if + //head should explode +.string headmodel; +.void() oldtouch; //These two are for when you're frozen and thaw out +.float oldmovetype; +.float target_scale; +.float scalerate; +.float blizzcount; +.float tripwire_cnt; +.float imp_count; +.vector proj_ofs; //Projectile offset, different from view_ofs. + +.string spawnername; //for monster spawner + +.entity catapulter; +.float catapult_time; +.float last_onground; //Timer- helps keep track of how long something has been in the air. +.vector pos_ofs; //Position ofset +.vector angle_ofs; //Angle offset +.float safe_time; //How long after a tornado throws you that it cant pick you up again +.float absorb_time; //for 0.3 seconds after crouching, you will absorb 1/2 of your falling damage upon impact +.float mintel; //Monster intelligence- temp since entity.hc was checked out +.vector wallspot; //Last place enemy was seen- for waypoint ai +.vector lastwaypointspot;//explains itself +.entity lockentity; //for waypoint system +.float last_impact; //Last time touch function was called + +.float inactive; +.float msg2; +.string msg3; +.string nexttarget; //For target transferral +.float upside_down; +.float lightvalue1; +.float lightvalue2; +.float fadespeed; +.float point_seq; //Waypoint sequence number +.float sheep_time; //How long you will be a sheep for +.float sheep_sound_time; +.float still_time; //How long she's been standing still +.float visibility_offset; //How hard it is to see and aim at entity, from 0 to 1 + //0 is totally visible, 1 is invisible +.float check_ok; //For trigger check, instead of re-using aflag +.entity check_chain; //for trigger_check, keeps track of it's targetted entities + +.void() th_spawn; //Monster function you spawned with +.float freeze_time; +.float level_frags; +.float visibility; + +entity sight_entity; //So monsters wake up other monsters +.entity viewentity; +.float sv_flags; //temp serverflags fix + +.float dmgtime; +.float healamount, healtype; +.float anglespeed; +.float angletime; +.float movetime; +.float hit_z; +.float torncount; +.entity path_last; +.float dflags; +.float gameFlags; +.entity targetPlayer; + +//MISSION PACK +.float fire_damage; +.float standard_grav; +.float init_exp_val; +.entity credit_enemy; +.string close_target; + +//SIEGE +.float cnt_grenades; +.float cnt_arrows; +.float last_time; +.float beast_time; +.float climbing; +.vector climbspot; +.float last_climb; +.float fov_val; +.float zoom_time; +.float fail_chance; +.void() th_init; +.vector init_org; +.string ondeath_target; +.string pain_target; + diff --git a/entity2.hc b/entity2.hc new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/entity2.hc @@ -0,0 +1 @@ + diff --git a/eric.hc b/eric.hc new file mode 100644 index 0000000..2c15d8f --- /dev/null +++ b/eric.hc @@ -0,0 +1,102 @@ +void()trap_fireball_use; +void trap_fireball_wait () +{ + self.use = trap_fireball_use; + self.think=SUB_Null; + self.nextthink=-1; +} + +void fireball_think () +{ + particle4(self.origin,3,random(160,176),PARTICLETYPE_FIREBALL,random(10,20)); + self.think=fireball_think; + thinktime self : 0.1; +} + +void trap_fireball_use () +{ +entity fireball; +vector vec; +float dot; + + if(self.spawnflags&1) + { + self.think=trap_fireball_wait; + thinktime self : 0; + } + else + { + self.use=trap_fireball_wait; + self.think = trap_fireball_use; + thinktime self : self.wait; + } + + if(self.goalentity) + self.enemy=self.goalentity; + else + self.enemy = find (world, classname, "player"); + + if((visible(self.enemy)&&self.enemy!=world)||self.goalentity==self.enemy) + { + vec=normalize((self.enemy.absmin+self.enemy.absmax)*0.5-self.origin); + makevectors(self.angles); + dot = v_forward*vec; + if(dot>0.6||self.goalentity==self.enemy) + { + sound (self, CHAN_WEAPON, "imp/fireball.wav", 1, ATTN_NORM); + fireball = spawn (); + fireball.movetype = MOVETYPE_FLYMISSILE; + fireball.solid = SOLID_BBOX; + fireball.speed=1000; + fireball.velocity=vec*fireball.speed; + fireball.touch = fireballTouch; + fireball.dmg=self.dmg; + fireball.owner = self; + fireball.angles = vectoangles (fireball.velocity); + fireball.think = fireball_think; + thinktime fireball : 0.05; + self.last_attack=time; + setmodel (fireball, "models/drgnball.mdl"); + setsize (fireball, '0 0 0', '0 0 0'); + setorigin (fireball,self.origin); + } + } +} + + +void locate_first_target () +{ + self.goalentity=find(world,targetname,self.target); + if(!self.goalentity) + dprint("ERROR: Targeted Fireball can't find target\n"); +} + +/*QUAKED trap_fireball (1 0.3 0) (0 0 0) (16 16 16) TRIGGER_ONLY +New item for QuakeEd +It works! It really works! +If TRIGGER_ONLY is turned on, it will fire once each time it's triggered (used) +otherwise, each time it's used, it's turned on or off. +If it's targetted to something, it will fire at that rather than tracking the player. +-------------------------FIELDS------------------------- +.wait = How long to wait between firings (default 0.5) +.dmg = How much damage to do with each shot (default 10) +-------------------------------------------------------- +*/ +void () trap_fireball = +{ + precache_sound2("imp/fireball.wav"); + precache_model2("models/drgnball.mdl"); + if(!self.wait) + self.wait=0.5; + if(!self.dmg) + self.dmg=10; + if(self.target) + { + self.think=locate_first_target; + thinktime self : 0.5; + } + + self.use = trap_fireball_use; +}; + + diff --git a/explode.hc b/explode.hc new file mode 100644 index 0000000..85f223c --- /dev/null +++ b/explode.hc @@ -0,0 +1,345 @@ +void() CB_BoltStick; +//void FireMeteor (string type); +//void FireAcidBlob (string type); + +void()BlowUp= +{ + if(self.dmg<2.5) + { + T_RadiusDamage (self, self.owner, self.dmg*100, world); + self.dmg += 0.1; + self.think=BlowUp; + thinktime self : 0.025; + } + else + { + self.think=SUB_Remove; + thinktime self : 0; + } +}; + +void() SprayFire= +{ + local entity fireballblast; + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_FIREBALL); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS_R); + + + fireballblast=spawn(); + fireballblast.effects (+) EF_NODRAW; + fireballblast.movetype=MOVETYPE_NOCLIP; + fireballblast.owner=self.owner; + fireballblast.classname="fireballblast"; + fireballblast.solid=SOLID_NOT; + setsize(fireballblast,'0 0 0','0 0 0'); + setorigin(fireballblast,self.origin); + fireballblast.dmg=0.1; + fireballblast.think=BlowUp; + thinktime fireballblast : 0; + remove(self); +}; + +void SmallExplosion (void) +{ + sound(self,CHAN_AUTO,"weapons/explode.wav",0.5,ATTN_NORM); + BecomeExplosion(CE_SM_EXPLOSION); +} + +void DarkExplosion () +{ + entity ignore; + + if(self.classname=="timebomb") + { + sound(self,CHAN_AUTO,"weapons/explode.wav",1,ATTN_NORM); + ignore=self.enemy; + } + else if(self.classname=="pincer") + { +// sound(self,CHAN_BODY,"weapons/explode.wav",1,ATTN_NORM); + ignore=self.owner; +// ignore = world; + } + else + { + if(self.controller.classname=="multigrenade") + sound(self.controller,CHAN_BODY,"weapons/explode.wav",1,ATTN_NORM); + else + sound(self,CHAN_AUTO,"weapons/explode.wav",1,ATTN_NORM); + ignore=world; + } + + T_RadiusDamage (self, self.owner, self.dmg, ignore); + + if(self.classname=="minigrenade"&&random()<0.5) + BecomeExplosion(FALSE); + else if(self.classname=="flaming arrow") + { + starteffect(CE_XBOW_EXPLOSION,self.origin); + remove(self); + } + else if (self.classname == "pincer") + { + endeffect(MSG_ALL,self.xbo_effect_id); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_DRILLA_EXPLODE); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS_R); + + remove(self); + } + else + { + starteffect(CE_NEW_EXPLOSION,self.origin); + remove(self); + } +} + +void() MultiExplode = +{ +float nummeteorites; +//FIXME: For some reason, the light casting effects in Hex2 +//are a lot more costly than they were in Quake... + if(self.classname=="stickmine") + { + SprayFire(); + return; + } + + T_RadiusDamage (self, self.owner, self.dmg, world); + + if(self.classname=="meteor"||self.classname=="acidblob") + { + nummeteorites=random(3,10); + if(deathmatch||coop) + { + if(self.classname=="acidblob") + { + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_CHUNK); + WriteCoord(MSG_MULTICAST, self.origin_x); + WriteCoord(MSG_MULTICAST, self.origin_y); + WriteCoord(MSG_MULTICAST, self.origin_z); + WriteCoord(MSG_MULTICAST, 0); + WriteCoord(MSG_MULTICAST, 0); + WriteCoord(MSG_MULTICAST, 300); + WriteByte(MSG_MULTICAST, self.thingtype); + WriteByte(MSG_MULTICAST, nummeteorites); + multicast(self.origin,MULTICAST_PHS_R); + } +// else +// starteffect(CE_CHUNK, self.origin, THINGTYPE_METEOR,'0 0 600', nummeteorites); + } +/* else while(nummeteorites>0) + { + if(self.classname=="acidblob")//FIXME: Need wet acid explode sound + { + if(nummeteorites==1) + sound(self,CHAN_BODY,"succubus/blobexpl.wav",1,ATTN_NORM); + FireAcidBlob("aciddrop"); + } + else + FireMeteor("minimeteor"); + nummeteorites =nummeteorites - 1; + }*/ + } +/* + if(self.classname=="meteor") + { + local float nummeteorites; + nummeteorites=random(3,10); + while(nummeteorites>0) + { + FireMeteor("minimeteor"); + nummeteorites =nummeteorites - 1; + } + } +*/ + if(self.flags2&FL_SMALL) + SmallExplosion(); + else + { + BecomeExplosion(FALSE); + } +}; + +void() SuperGrenadeExplode; +void() GrenadeTouch2 = +{ + if (other == self.owner) + return; // don't explode on owner + + if(other.owner==self.owner&&other.classname==self.classname&&self.classname=="minigrenade") + return; + + if (other.takedamage==DAMAGE_YES)//let them damage b_models on impact? + { + if(self.classname=="minigrenade") + {//special case- does 50 pts to other, 25rad to everyone else + if(other.solid==SOLID_BSP&&other.thingtype==THINGTYPE_METAL) + self.dmg/=2;//less damage to metal doors, 25 direct, 12.5 rad + T_Damage(other,self,self.owner,self.dmg); + T_RadiusDamage (self, self.owner, self.dmg/2, other); + self.dmg=0; + self.think=DarkExplosion; + thinktime self : 0; + return; + } + else + { + T_Damage(other,self,self.owner,self.dmg); + self.dmg/=2; + } + if(self.classname=="multigrenade") + self.think=SuperGrenadeExplode; + else if(self.classname=="flaming arrow")//self.classname=="minigrenade"|| + self.think=DarkExplosion; + else + self.think=MultiExplode; + thinktime self : 0; + } + else + { + sound (self, CHAN_WEAPON, "assassin/gbounce.wav", 1, ATTN_NORM); // bounce sound + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; + } +}; + +void StickMineStick () +{ + if(self.wait<=time) + self.think=MultiExplode; + else if(self.enemy.health<=0&&self.health) + { + self.health=0; + self.movetype=MOVETYPE_BOUNCE; + self.velocity_z=random(-100,100); + self.avelocity=RandomVector('50 50 50'); + } + else if(self.movetype!=MOVETYPE_BOUNCE) + { + setorigin(self,self.enemy.origin+self.view_ofs); + self.angles=self.o_angle + self.enemy.angles; + self.think=StickMineStick; + } + thinktime self : 0; +} + +void() StickMineTouch = +{ + if(other==self.owner) + return; + + self.skin=1; +vector stickdir; + self.touch=SUB_Null; + if(other.takedamage) + { + sound(self,CHAN_WEAPON,"weapons/met2flsh.wav",1,ATTN_NORM); + T_Damage(other,self,self.owner,3); + if(other.solid!=SOLID_BSP) + { +// makevectors(self.angles); + stickdir=other.origin+normalize(self.origin-other.origin)*12; +//Modify height for shorter or taller models like imp, golem, spider, etc. + if(other.classname=="player") +//Put it right below view of player + stickdir_z=other.origin_z+other.proj_ofs_z + 1; + else if(other.classname=="monster_spider") + stickdir_z=(self.origin_z+(other.origin_z+other.size_z*0.2)*3)*0.25; + else stickdir_z=(self.origin_z+(other.origin_z+other.size_z*0.6)*3)*0.25; + setorigin(self,stickdir); + SpawnPuff(self.origin+v_forward*8,'0 0 0'-v_forward*24,10,other); + } + } + else + { + setorigin(self,self.origin+normalize(self.velocity)*-3); + sound(self,CHAN_WEAPON,"weapons/met2stn.wav",1,ATTN_NORM); + SpawnPuff(self.origin+v_forward*8,'0 0 0'-v_forward*24,10,world); + } + + self.velocity='0 0 0'; + self.movetype=MOVETYPE_NOCLIP; + self.solid=SOLID_NOT; + self.touch=SUB_Null; + self.wait=time + 1; + self.health=other.health; + if(other.takedamage) + { + self.enemy=other; + self.view_ofs=(self.origin-other.origin); + self.o_angle=(self.angles-self.enemy.angles); + //self.enemy=world; + self.movetype=MOVETYPE_NONE; + //self.think=MultiExplode; + self.think=StickMineStick; + thinktime self : 0; + } + else + { + self.enemy=world; + self.movetype=MOVETYPE_NONE; + self.think=MultiExplode; + thinktime self : 0.5; + } +}; + +void() Use_Fireball = +{ + self.attack_finished=time + 1;//So you can't have a ton of them + makevectors(self.v_angle); +//sound +entity missile; + missile=spawn(); + missile.owner=self; + missile.classname="stickmine"; + missile.movetype=MOVETYPE_BOUNCE; + missile.solid=SOLID_BBOX; + missile.touch=StickMineTouch; + missile.dmg=50; + + missile.velocity=normalize(v_forward)*700 +v_up*200; + missile.avelocity=RandomVector('300 300 300'); + missile.lifetime=time+60; + + setmodel (missile, "models/glyphwir.mdl"); + setsize(missile,'0 0 0','0 0 0'); + setorigin(missile,self.origin+self.proj_ofs+v_forward*16); + missile.think=MultiExplode; + thinktime missile : 10; +}; + +float GetImpactType (entity impacted) +{ + float hittype; + + if (impacted.classname == "mummy")//mummys don't bleed + hittype = XBOW_IMPACT_MUMMY; + else if (impacted.classname == "spider")//spiders bleed green + hittype = XBOW_IMPACT_GREENFLESH; + else if (impacted.thingtype == THINGTYPE_FLESH) + hittype = XBOW_IMPACT_REDFLESH; + else if (impacted.thingtype == THINGTYPE_WOOD||impacted.thingtype==THINGTYPE_DIRT) + hittype = XBOW_IMPACT_WOOD; + else if ((impacted.thingtype==THINGTYPE_GREYSTONE) || (impacted.thingtype==THINGTYPE_BROWNSTONE)) + hittype = XBOW_IMPACT_STONE; + else if (impacted.thingtype==THINGTYPE_METAL) + hittype = XBOW_IMPACT_METAL; + else if (impacted.thingtype==THINGTYPE_ICE) + hittype = XBOW_IMPACT_ICE; + else + hittype = XBOW_IMPACT_DEFAULT; + + return (hittype); +} + diff --git a/fablade.hc b/fablade.hc new file mode 100644 index 0000000..6b49757 --- /dev/null +++ b/fablade.hc @@ -0,0 +1,86 @@ +/* + * $Header: /HexenWorld/Siege/FAblade.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\Fangel\wingblad\FAblade.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\Fangel\wingblad +$origin 0 0 0 +$base BASE skin1 +$skin skin1 +$flags 0 + +// +$frame BLADE + + +void() faBladeTouch = +{ +float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + damg = random(8,16); + + if (other.health) + T_Damage (other, self, self.owner, damg ); + + + sound (self, CHAN_WEAPON, "weapons/expsmall.wav", 1, ATTN_NORM); + self.origin = self.origin - 8*normalize(self.velocity); + CreateGreenSmoke(self.origin, '0 0 8', HX_FRAME_TIME * 4); + remove(self); +}; + + +// Frame Code +void() frame_BLADE = [ $BLADE , frame_BLADE ] { }; + + + + +void(vector offset, float set_speed, vector dest_offset) do_faBlade = +{ +entity missile; +vector vec; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.flags = FL_FLY; + missile.health = 10; + missile.drawflags=MLS_ABSLIGHT; + missile.abslight=0.5; + + setmodel (missile, "models/fablade.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + +// set missile speed + + makevectors (self.angles); + setorigin (missile, self.origin + v_factor(offset)); + + vec = self.enemy.origin - missile.origin + self.enemy.proj_ofs + dest_offset; + vec = normalize(vec); + + missile.velocity = (vec+aim_adjust(self.enemy))*set_speed; + missile.angles = vectoangles(missile.velocity); + + missile.touch = faBladeTouch; +}; + diff --git a/famhorse.hc b/famhorse.hc new file mode 100644 index 0000000..94ad3e4 --- /dev/null +++ b/famhorse.hc @@ -0,0 +1,806 @@ +/* + * $Header: /HexenWorld/Siege/famhorse.hc 4 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\RdrFam\Horse\Final\famhorse.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\RdrFam\Horse\Final +$origin 0 0 0 +$base base skin +$skin skin +$flags 0 + +// Horse frames +$frame Hrear1 Hrear2 Hrear3 Hrear4 Hrear5 +$frame Hrear6 Hrear7 Hrear8 Hrear9 Hrear10 +$frame Hrear11 Hrear12 Hrear13 Hrear14 Hrear15 +$frame Hrear16 Hrear17 Hrear18 Hrear19 Hrear20 +$frame Hrear21 Hrear22 Hrear23 Hrear24 Hrear25 +$frame Hrear26 Hrear27 Hrear28 Hrear29 Hrear30 +$frame Hrear31 Hrear32 Hrear33 Hrear34 Hrear35 +$frame Hrear36 Hrear37 Hrear38 Hrear39 Hrear40 +$frame Hrear41 Hrear42 Hrear43 Hrear44 Hrear45 +$frame Hrear46 Hrear47 Hrear48 Hrear49 Hrear50 + +// +$frame HtranA1 HtranA2 HtranA3 HtranA4 HtranA5 +$frame HtranA6 HtranA7 HtranA8 HtranA9 HtranA10 +$frame HtranA11 HtranA12 HtranA13 HtranA14 HtranA15 +$frame HtranA16 + +// +$frame HtranB1 HtranB2 HtranB3 HtranB4 HtranB5 +$frame HtranB6 HtranB7 HtranB8 HtranB9 HtranB10 +$frame HtranB11 HtranB12 HtranB13 HtranB14 HtranB15 +$frame HtranB16 + +// +$frame Htrot1 Htrot2 Htrot3 Htrot4 Htrot5 +$frame Htrot6 Htrot7 Htrot8 Htrot9 Htrot10 +$frame Htrot11 Htrot12 + +$framevalue 0 +//---------------------------------------------------------------- +// Rider Frames +//---------------------------------------------------------------- +$frame Frear1 Frear2 Frear3 Frear4 Frear5 +$frame Frear6 Frear7 Frear8 Frear9 Frear10 +$frame Frear11 Frear12 Frear13 Frear14 Frear15 +$frame Frear16 Frear17 Frear18 Frear19 Frear20 +$frame Frear21 Frear22 Frear23 Frear24 Frear25 +$frame Frear26 Frear27 Frear28 Frear29 Frear30 +$frame Frear31 Frear32 Frear33 Frear34 Frear35 +$frame Frear36 Frear37 Frear38 Frear39 Frear40 +$frame Frear41 Frear42 Frear43 Frear44 Frear45 +$frame Frear46 Frear47 Frear48 Frear49 Frear50 + +// +$frame Fscale1 Fscale2 Fscale3 Fscale4 Fscale5 +$frame Fscale6 Fscale7 Fscale8 Fscale9 Fscale10 +$frame Fscale11 Fscale12 Fscale13 Fscale14 Fscale15 +$frame Fscale16 Fscale17 Fscale18 Fscale19 Fscale20 +$frame Fscale21 Fscale22 Fscale23 Fscale24 Fscale25 +$frame Fscale26 Fscale27 Fscale28 Fscale29 Fscale30 +$frame Fscale31 Fscale32 Fscale33 Fscale34 Fscale35 +$frame Fscale36 Fscale37 Fscale38 Fscale39 Fscale40 +$frame Fscale41 Fscale42 Fscale43 Fscale44 Fscale45 +$frame Fscale46 Fscale47 Fscale48 Fscale49 Fscale50 +$frame Fscale51 Fscale52 Fscale53 Fscale54 Fscale55 +$frame Fscale56 Fscale57 Fscale58 Fscale59 Fscale60 +$frame Fscale61 Fscale62 Fscale63 Fscale64 Fscale65 +$frame Fscale66 Fscale67 Fscale68 Fscale69 Fscale70 + +// +$frame FtranA1 FtranA2 FtranA3 FtranA4 FtranA5 +$frame FtranA6 FtranA7 FtranA8 FtranA9 FtranA10 +$frame FtranA11 FtranA12 FtranA13 FtranA14 FtranA15 +$frame FtranA16 + +// +$frame FtranB1 FtranB2 FtranB3 FtranB4 FtranB5 +$frame FtranB6 FtranB7 FtranB8 FtranB9 FtranB10 +$frame FtranB11 FtranB12 FtranB13 FtranB14 FtranB15 +$frame FtranB16 + +// +$frame Ftrot1 Ftrot2 Ftrot3 Ftrot4 Ftrot5 +$frame Ftrot6 Ftrot7 Ftrot8 Ftrot9 Ftrot10 +$frame Ftrot11 Ftrot12 Ftrot13 Ftrot14 Ftrot15 +$frame Ftrot16 + + +float fam_start[1] = +{ + $Htrot1 +}; + +float fam_end[1] = +{ + $Htrot12 +}; + +float fam_speed[1] = +{ + 5.5 // Normal speed +}; + +// Array to align frames +float FamRiderFrames[5] = +{ + $Ftrot1, // Animation for fast gallop + + $FtranA1, // Animation for start of rear + $Frear1, // Animation for rear + $FtranB1, // Animation for end of rear + + $Fscale1 // Attack Sequence #1 +}; + +float FH_STAGE_NORMAL = 0; +float FH_STAGE_BEGIN_REAR = 1; +float FH_STAGE_MIDDLE_REAR = 2; +float FH_STAGE_END_REAR = 3; +float FH_STAGE_ATTACK = 4; +float FH_STAGE_STANDING = 5; +float FH_STAGE_LAUGHING = 6; +float FH_STAGE_ATTACK2 = 7; + +float pulltime; +float looktime; +float hurttime; + +void famhorse_move(void); +void famhorse_rear(void); + +void do_fambeam (entity lowner,float tag, float lflags, float duration, vector spot1, vector spot2) +{ + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_STREAM_FAMINE); + WriteEntity (MSG_BROADCAST, lowner); + WriteByte (MSG_BROADCAST, tag+lflags); + WriteByte (MSG_BROADCAST, duration); + + WriteCoord (MSG_BROADCAST, spot1_x); + WriteCoord (MSG_BROADCAST, spot1_y); + WriteCoord (MSG_BROADCAST, spot1_z); + + WriteCoord (MSG_BROADCAST, spot2_x); + WriteCoord (MSG_BROADCAST, spot2_y); + WriteCoord (MSG_BROADCAST, spot2_z); +} + +void famine_pain(void) +{ + float chance,rear_chance; + + rear_chance = self.health / self.max_health; + + if (rear_chance < .50) + rear_chance = .5; + + if (self.monster_stage == FH_STAGE_NORMAL) + { + // Force a new gallop frame in + self.frame = fam_start[self.rider_gallop_mode]; + + chance = random(); + + if (chance > rear_chance) // Like the Lone Ranger but he disappears + { + self.think = famhorse_rear; + self.monster_stage = FH_STAGE_BEGIN_REAR; + } + else if (chance < 0.20) // Told himself a joke + { + self.monster_stage = FH_STAGE_LAUGHING; + self.movechain.frame = $FtranB1; + } + else if (chance < 0.60) // Missile attack + { + self.monster_stage = FH_STAGE_ATTACK2; + self.movechain.frame = $Fscale1; + } + } +} + +void famine_blinkin(void) +{ + thinktime self : HX_FRAME_TIME; + self.think = famine_blinkin; + + self.scale += 0.10; + self.movechain.scale += 0.10; + + if (self.scale >= 1) + { + self.scale=1; + self.movechain.scale=1; + + thinktime self : HX_FRAME_TIME; + self.think = famhorse_rear; + } +} + +// Find a point to start at close to the player +vector famine_pointcheck(void) +{ + entity search; + float diff, holddiff; + vector newspot,holdpos; + + search = find(world, classname, "rider_path"); + diff = 99999; + while(search != world) + { + holddiff = vlen(search.origin - self.enemy.origin); + + if (holddiff < diff) + { + traceline (search.origin, search.origin - '0 0 600' , FALSE, self); + + holdpos=trace_endpos; + tracearea (holdpos,holdpos + '0 0 40','-55 -55 -24', '55 55 150',FALSE,self); + if (trace_fraction == 1.0 && trace_ent == world) // Check no one is standing where monster wants to be + { + diff = holddiff; + newspot= holdpos; + self.path_current = search; + } + } + + search = find(search, classname, "rider_path"); + } + return (newspot); +} + + +/*----------------------------------------- + famine_init - looking for a spot to come back in + -----------------------------------------*/ +void famine_blinkin_init (void) +{ + vector holdspot; + holdspot = famine_pointcheck(); + setorigin(self,holdspot); + + setmodel (self, "models/boss/famhorse.mdl"); + setsize (self, '-40 -40 0', '40 40 100'); + self.hull = HULL_POINT; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_YES; + + setmodel (self.movechain, "models/boss/famrider.mdl"); + self.movechain.flags (+) FL_MOVECHAIN_ANGLE; + + walkmove(self.angles_y, .01, TRUE); // You have to move it a little bit to make it solid + + riderpath_findnext(); // Find the next path point to turn the horse in that direction + + self.ideal_yaw = vectoyaw(self.path_current.origin - self.origin); + self.angles_y = self.ideal_yaw; + + sound (self, CHAN_BODY, "skullwiz/blinkin.wav", 1, ATTN_NORM); + CreateRedCloud (self.origin + '0 0 40','0 0 0',HX_FRAME_TIME); + + thinktime self : HX_FRAME_TIME; + self.think = famine_blinkin; +} + +/*----------------------------------------- + famine_blinkout - blink out + -----------------------------------------*/ +void famine_blinkout(void) +{ + thinktime self : HX_FRAME_TIME / 2; + self.think = famine_blinkout; + + self.scale -= 0.10; + self.movechain.scale -= 0.10; + + if ((self.scale > 0.79) && (self.scale < 0.89)) + { + sound (self, CHAN_BODY, "skullwiz/blinkout.wav", 1, ATTN_NORM); + CreateRedCloud (self.origin + '0 0 40','0 0 0',HX_FRAME_TIME); + } + + if (self.scale < 0.10) + { + setmodel(self,string_null); + setmodel(self.movechain,string_null); + thinktime self : random(0.5,3); // Reappear when + self.think = famine_blinkin_init; + } +} + +void famine_blinkout_init(void) +{ + self.takedamage = DAMAGE_NO; // So t_damage won't force him into another state + self.solid = SOLID_NOT; + self.scale = 1; + self.drawflags (+) SCALE_TYPE_XYONLY; + + self.movechain.takedamage = DAMAGE_NO; // So t_damage won't force him into another state + self.movechain.scale = 1; + self.movechain.drawflags (+) SCALE_TYPE_XYONLY; + + famine_blinkout(); +} + +void famine_missile_touch(void) +{ + float damg; + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + damg = random(8,16); + + T_Damage (other, self, self.owner, damg ); + + self.origin = self.origin - 8 * normalize(self.velocity) - '0 0 40'; + sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + + CreateRedSpark (self.origin); + + remove(self); + +} + + +void famine_missile_think (void) +{ + if (self.lifetime < time) + { + sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + CreateRedSpark (self.origin); + remove(self); + } + else + { + HomeThink(); + self.angles = vectoangles(self.velocity); + self.think=famine_missile_think; + thinktime self : HX_FRAME_TIME; + } +} + +void famine_missile(float dir) +{ + entity newmis; + vector diff; + + newmis = spawn (); + newmis.owner = self; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_BBOX; + + setmodel (newmis, "models/famshot.mdl"); + setsize (newmis, '0 0 0', '0 0 0'); + setorigin (newmis, self.origin + '0 0 120'); + + newmis.angles = self.angles; + + diff = (self.enemy.origin + self.enemy.view_ofs) - self.origin + '0 0 120' ; + newmis.velocity = normalize(diff); + newmis.angles = vectoangles(newmis.velocity); + + if (dir == 0) + newmis.angles_y -= 25; + else if (dir == 2) + newmis.angles_y += 25; + makevectors (newmis.angles); + + + newmis.velocity = normalize(v_forward); + if (dir ==1) + newmis.speed=800; //Speed + else + newmis.speed=700; //Speed + newmis.classname = "faminemissile"; + newmis.angles = vectoangles(newmis.velocity); + + newmis.veer=FALSE; //No random wandering + newmis.turn_time=5; //Lower the number, tighter the turn + newmis.ideal_yaw=FALSE;//Only track things in front + newmis.lifetime = time + 2; + newmis.think=famine_missile_think; + thinktime newmis : 0; + + newmis.touch = famine_missile_touch; +} + +void famine_missilespawner(void) +{ + CreateRedFlash(self.origin + '0 0 120'); + sound (self, CHAN_WEAPON, "famine/shot.wav", 1, ATTN_NORM); + famine_missile(0); + famine_missile(1); + famine_missile(2); +} + +/* --------------------------- + Create the rider + ---------------------------*/ +void create_famrider(entity horse) +{ + entity rider; + + rider = spawn(); + + rider.solid = SOLID_NOT; + rider.movetype = MOVETYPE_NONE; + rider.origin = horse.origin; + rider.angles = self.angles; + + setmodel (rider, "models/boss/famrider.mdl"); + rider.skin = 0; + + horse.movechain = rider; + rider.flags (+) FL_MOVECHAIN_ANGLE; +} + +/* --------------------------- + The horse is rearing + ---------------------------*/ +void famhorse_rear(void) +{ + float retval; + + thinktime self : HX_FRAME_TIME; + + if (self.monster_stage == FH_STAGE_BEGIN_REAR) + { + retval = AdvanceFrame($HtranA1,$HtranA16); + + if (self.frame > $HtranA10) + self.speed = 1; + + riderpath_move(self.speed); + + if (self.frame == $HtranA8) + sound (self, CHAN_VOICE, "famine/whinny.wav", 1, ATTN_NORM); + + if (retval == AF_END) + self.monster_stage = FH_STAGE_MIDDLE_REAR; + self.movechain.frame = FamRiderFrames[1] + (self.frame - $HtranA1); + } + else if (self.monster_stage == FH_STAGE_MIDDLE_REAR) + { + retval = AdvanceFrame($Hrear1,$Hrear50); + + if (self.frame == $Hrear10) + { + famine_blinkout_init(); + return; + } + + if (self.enemy) + { + if (self.enemy.health > 0) + { + if (self.frame == $Hrear30) + famine_missilespawner(); + } + } + + if (retval == AF_END) + { + if (self.enemy != world && random() < 0.7) + self.monster_stage = FH_STAGE_STANDING; + else + self.monster_stage = FH_STAGE_END_REAR; + } + self.movechain.frame = FamRiderFrames[2] + (self.frame - $Hrear1); + + } + else if (self.monster_stage == FH_STAGE_STANDING) + { + if (random() < 0.5) + self.monster_stage = FH_STAGE_END_REAR; + } + else if (self.monster_stage == FH_STAGE_END_REAR) + { + retval = AdvanceFrame($HtranB1,$HtranB16); + + if (self.frame < $HtranB11) + self.speed =0; + else if (self.frame < $HtranB13) + self.speed = fam_speed[self.rider_gallop_mode] * .5; + else + self.speed = fam_speed[self.rider_gallop_mode]; + + if (retval == AF_END) + { + self.think = famhorse_move; + self.monster_stage = FH_STAGE_NORMAL; + } + + riderpath_move(self.speed); + + self.movechain.frame = FamRiderFrames[3] + (self.frame - $HtranB1); + } +} + +void check_remove () +{ + thinktime self : 1; + if(pulltime rear_chance) // Like the Lone Ranger but he disappears + { + self.think = famhorse_rear; + self.monster_stage = FH_STAGE_BEGIN_REAR; + } + else if (chance < 0.05) // Told himself a joke + { + self.monster_stage = FH_STAGE_LAUGHING; + self.movechain.frame = $FtranB1; + } + // Find an enemy?? + else if ((self.rider_gallop_mode == 0) && (looktime < time)) + { + traceline (self.origin + '0 0 120',self.enemy.origin , FALSE, self); + + if (self.enemy) + { + if (self.enemy == trace_ent) + { + chance = random(); + + if (chance < .30) // The famous pull attack + { + pulltime = time + random(2,5); + self.monster_stage = FH_STAGE_ATTACK; + self.movechain.frame = $Fscale1; + sound(self,CHAN_WEAPON,"famine/pull.wav",1,ATTN_NORM); + } + else if (chance < .70) // Missile attack + { + self.monster_stage = FH_STAGE_ATTACK2; + self.movechain.frame = $Fscale1; + } + } + } + } + } + + // Is rider attacking player + if (self.monster_stage == FH_STAGE_ATTACK) + { + if ((self.movechain.frame == $Fscale9) && (self.enemy.health > 0)) + { + newent = spawn(); + setorigin (newent, self.origin + '0 0 120'); + setmodel (newent, "models/soulball.mdl"); + self.controller = newent; + self.controller.think=check_remove; + thinktime self.controller : 0; + } + + if ((self.movechain.frame == $Fscale10) && (self.enemy.health > 0)) + { + diff = self.enemy.origin - self.origin + '0 0 120'; + holdvel = normalize(diff); + holdangles = vectoangles(holdvel); + + // traceline in front and behind because the beam is wide + makevectors (holdangles); + spot1 = self.origin + '0 0 120' + v_right * 25; + traceline (spot1,self.enemy.origin , FALSE, self); + if (trace_ent != self.enemy) + { + pulltime = 0; + } + else + { + spot1 = self.origin + '0 0 120' - v_right * 25; + traceline (spot1,self.enemy.origin , FALSE, self); + if (trace_ent != self.enemy) + pulltime = 0; + } + + if (pulltime) + { + self.movechain.drawflags(+)MLS_ABSLIGHT; + self.movechain.abslight = .5; + do_fambeam (self,1,STREAM_ATTACHED, 1, self.origin + '0 0 120', self.enemy.origin); + self.enemy.velocity = '0 0 0'; + + setorigin (self.controller, self.origin + '0 0 120'); + + diff = self.enemy.origin - self.origin; + hold_velocity = normalize(diff); + hold_velocity = hold_velocity * -250; + self.enemy.velocity = self.enemy.velocity + hold_velocity; + if(vlen(self.enemy.velocity)>500) + self.enemy.velocity=normalize(self.enemy.velocity)*500; + self.enemy.flags (-) FL_ONGROUND; + } + + if (hurttime < time) + { + diff2 = vlen(self.enemy.origin - self.origin); + damage = 300/diff2; + if (damage < 2) + damage=2; + else if (damage >8) + damage = 8; + + T_Damage (self.enemy, self, self, damage); + if (self.enemy.health <= 0) + { + if(self.controller) + remove(self.controller); + stopSound(self,CHAN_WEAPON); + //sound(self,CHAN_WEAPON,"misc/null.wav",1,ATTN_NORM); + } + + hurttime = time + 1; + } + + if (pulltime < time) + { + if(self.controller) + remove(self.controller); + stopSound(self,CHAN_WEAPON); + //sound(self,CHAN_WEAPON,"misc/null.wav",1,ATTN_NORM); + + self.movechain.drawflags(-)MLS_ABSLIGHT; + self.movechain.frame += 50; + looktime = time + random(5,10); + } + } + else + { + self.movechain.frame += 1; + } + + if (self.movechain.frame >= $Fscale70) + self.monster_stage = FH_STAGE_NORMAL; + } + else if (self.monster_stage == FH_STAGE_ATTACK2) + { + if (self.movechain.frame == $Fscale10) + { + famine_missilespawner(); + self.movechain.frame += 50; + } + + self.movechain.frame += 1; + + if (self.movechain.frame >= $Fscale70) + self.monster_stage = FH_STAGE_NORMAL; + } + + else if (self.monster_stage == FH_STAGE_LAUGHING) + { + self.movechain.frame += 1; + + if (self.movechain.frame == $FtranB6) + sound (self.movechain, CHAN_VOICE, "famine/laugh.wav", 1, ATTN_NORM); + + else if (self.movechain.frame >= $FtranB16) + self.monster_stage = FH_STAGE_NORMAL; + } +} + +/*QUAKED rider_famine (1 0 0) (-55 -55 -24) (55 55 150) TRIGGER_WAIT +Famine rider monster. You must place rider_path entites +on the map. The rider will first proceed to the +rider_path point with a path_id of 1. +-------------------------FIELDS------------------------- +map: next map to go to when you kill the rider +target: start spot on the next map +-------------------------------------------------------- +*/ +void rider_famine(void) +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model3 ("models/boss/famhorse.mdl"); + precache_model3 ("models/boss/famrider.mdl"); + + precache_model3 ("models/famshot.mdl"); + + precache_sound3 ("famine/die.wav"); + precache_sound3 ("famine/laugh.wav"); + precache_sound3 ("famine/whinny.wav"); + precache_sound3 ("famine/pull.wav"); + precache_sound3 ("famine/shot.wav"); + precache_sound3 ("famine/snort.wav"); + precache_sound3 ("famine/clop1.wav"); + precache_sound3 ("famine/clop2.wav"); + precache_sound3 ("famine/clop3.wav"); + precache_sound3 ("misc/null.wav"); + precache_sound3 ("raven/blast.wav"); + precache_sound3 ("skullwiz/blinkout.wav"); + precache_sound3 ("skullwiz/blinkin.wav"); + + rider_init(); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.thingtype = THINGTYPE_FLESH; + self.yaw_speed = 2; + + setmodel (self, "models/boss/famhorse.mdl"); + self.skin = 0; + + setsize (self, '-40 -40 0', '40 40 100'); + self.health = self.max_health = 2200; + self.th_pain = famine_pain; + self.rider_gallop_mode = 0; + self.speed = fam_speed[self.rider_gallop_mode]; + self.rider_path_distance = 75; + self.monster_stage = FH_STAGE_NORMAL; + self.mass = 30000; + self.flags (+) FL_MONSTER; + self.flags2 (+) FL_ALIVE; + self.monsterclass = CLASS_BOSS; + self.yaw_speed = 10; + self.experience_value = 500; + + create_famrider(self); + self.attack_finished = 0; + self.hull = HULL_POINT; + looktime =0; + hurttime = 0; + + self.noise="famine/die.wav"; + self.th_save = famhorse_move; + self.think = multiplayer_health; + thinktime self : 1; +} + diff --git a/fangel.hc b/fangel.hc new file mode 100644 index 0000000..7379456 --- /dev/null +++ b/fangel.hc @@ -0,0 +1,895 @@ +/* + * $Header: /HexenWorld/Siege/fangel.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\Fangel\final\fangel.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\Fangel\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + + +// +$frame fblock1 fblock2 fblock3 fblock4 fblock5 +$frame fblock6 fblock7 fblock8 fblock9 fblock10 +$frame fblock11 fblock12 fblock13 fblock14 fblock15 +$frame fblock16 fblock17 fblock18 fblock19 fblock20 +$frame fblock21 + +// +$frame fdeth1 fdeth2 fdeth3 fdeth4 fdeth5 +$frame fdeth6 fdeth7 fdeth8 fdeth9 fdeth10 +$frame fdeth11 fdeth12 fdeth13 fdeth14 fdeth15 +$frame fdeth16 fdeth17 fdeth18 fdeth19 fdeth20 +$frame fdeth21 fdeth22 fdeth23 fdeth24 fdeth25 +$frame fdeth26 fdeth27 fdeth28 fdeth29 fdeth30 +$frame fdeth31 fdeth32 fdeth33 fdeth34 fdeth35 +$frame fdeth36 fdeth37 fdeth38 fdeth39 fdeth40 + +// +$frame ffly1 ffly2 ffly3 ffly4 ffly5 +$frame ffly6 ffly7 ffly8 ffly9 ffly10 +$frame ffly11 ffly12 ffly13 ffly14 ffly15 +$frame ffly16 ffly17 ffly18 ffly19 ffly20 +$frame ffly21 ffly22 ffly23 ffly24 ffly25 +$frame ffly26 ffly27 ffly28 ffly29 ffly30 + +// +$frame fhand1 fhand2 fhand3 fhand4 fhand5 +$frame fhand6 fhand7 fhand8 fhand9 fhand10 +$frame fhand11 fhand12 fhand13 fhand14 fhand15 +$frame fhand16 fhand17 fhand18 fhand19 fhand20 +$frame fhand21 fhand22 + +// +$frame fmove1 fmove2 fmove3 fmove4 fmove5 +$frame fmove6 fmove7 fmove8 fmove9 fmove10 +$frame fmove11 fmove12 fmove13 fmove14 fmove15 +$frame fmove16 fmove17 fmove18 fmove19 fmove20 + +// +$frame fpain1 fpain2 fpain3 fpain4 fpain5 +$frame fpain6 fpain7 fpain8 fpain9 fpain10 +$frame fpain11 fpain12 + +// +$frame ftranA1 ftranA2 ftranA3 ftranA4 ftranA5 +$frame ftranA6 ftranA7 ftranA8 ftranA9 ftranA10 +$frame ftranA11 ftranA12 ftranA13 ftranA14 ftranA15 +$frame ftranA16 ftranA17 ftranA18 ftranA19 ftranA20 + +// +$frame ftranB1 ftranB2 ftranB3 ftranB4 ftranB5 +$frame ftranB6 ftranB7 ftranB8 ftranB9 ftranB10 +$frame ftranB11 ftranB12 ftranB13 ftranB14 ftranB15 +$frame ftranB16 ftranB17 ftranB18 ftranB19 ftranB20 + +// +$frame fwing1 fwing2 fwing3 fwing4 fwing5 +$frame fwing6 fwing7 fwing8 fwing9 fwing10 +$frame fwing11 fwing12 fwing13 fwing14 fwing15 +$frame fwing16 fwing17 fwing18 fwing19 fwing20 +$frame fwing21 fwing22 fwing23 fwing24 fwing25 +$frame fwing26 fwing27 fwing28 fwing29 fwing30 + + +// Function protos +void() fangel_blockframes; +void fangel_handframes (void); +void fangel_wingframes (void); +void fangel_flyframes (void); + +// Constants +float fangel_attack_speed = 11; +float fangel_move_speed = 6; + +float () fangel_check_incoming = +{ +entity item; +vector vec, realVec; +float dot; + + if(range(self.enemy)<=RANGE_MELEE) + return FALSE; + + if(fov(self,self.enemy,30)&&self.enemy.last_attack+0.75>time) + { + self.th_save = self.think; + self.fangel_Count = 0; + fangel_blockframes(); + return TRUE; + } + + if(random()>0.4 + skill/10 + self.skin/10) + return FALSE; + + item = findradius(self.origin, 256); + while (item) + { + if (item.owner.classname == "player" && (item.movetype == MOVETYPE_FLYMISSILE || + item.movetype == MOVETYPE_BOUNCEMISSILE || item.movetype==MOVETYPE_BOUNCE)) + { + vec = normalize(self.origin - item.origin + self.view_ofs); + realVec = normalize(item.velocity); + dot= vec*realVec; + if (dot >= 0.4) + { + self.th_save = self.think; + self.fangel_Count = 0; + fangel_blockframes(); + return TRUE; + } + } + item = item.chain; + } + return FALSE; +}; + +// Monster Stages +float FANGEL_STAGE_WAIT = 0; +float FANGEL_STAGE_FLY = 1; +float FANGEL_STAGE_FLOAT = 2; +float FANGEL_STAGE_SIDESTEP = 3; +//float FANGEL_STAGE_STRAIGHT = 3; +//float FANGEL_STAGE_REVERSE = 4; +//float FANGEL_STAGE_ATTACK = 10; + +void() fangel_check_wing = +{ +float retval; + + if(!self.enemy) + return; + + enemy_infront = visible(self.enemy); + + // If we are flying, don't attack as often + if (self.monster_stage == FANGEL_STAGE_FLY && random() < 0.5) + enemy_infront = 0; + + if (enemy_infront) + { + self.th_save = self.think; + enemy_range = range (self.enemy); + if (random() < 0.5) + retval = CheckMonsterAttack(MA_FAR_MELEE,1); + else + retval = CheckMonsterAttack(MA_MISSILE,1); + } + else retval = MA_NOATTACK; + + if (retval != MA_SUCCESSFUL) + fangel_check_incoming(); + else + self.yaw_speed = fangel_attack_speed; +}; + +void fangel_find_spot (void) +{ +float crj, radius,dist; +vector vec; + + crj=0; + while(crj < 50) + { + radius = random(100,200); + + vec = randomv('0 0 0', '360 360 0'); + + vec = normalize(vec); + vec = self.enemy.origin + vec*radius; + + vec_z = vec_z + random(20, 40) + self.enemy.view_ofs_z; + + tracearea (self.origin,vec,self.mins,self.maxs,FALSE,self); + if (trace_fraction == 1) + { + self.monster_last_seen = vec; + + dist = self.origin_z - self.monster_last_seen_z; + + if (dist < -20) + self.z_movement = random(0,2); + else if (dist > 20 ) + self.z_movement = random(-2,0); + else + self.z_movement = random(-2,2); // Give her a little up and down movement + + self.z_duration = time + HX_FRAME_TIME * random(15,25); + + return; + } + crj += 1; + } + + self.monster_stage = FANGEL_STAGE_FLOAT; + self.monster_duration = random(20,30); +} + +void() fangel_init = +{ // Set the fallen angel ready + dprint(self.enemy.classname); + dprint("- Found enemy\n"); + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.think=self.th_stand; + thinktime self : random(.1,.6); + self.count = 0; + self.monster_stage = FANGEL_STAGE_FLY; + self.monster_duration = 0; + self.goalentity = self.enemy; + + self.monster_awake = TRUE; + + if (self.skin) + self.drawflags (+) MLS_POWERMODE; + + fangel_find_spot(); +}; + + +void fangel_wait (void) +{ + thinktime self : 0.15; + LocateTarget(); + if(self.enemy) // We found a target + fangel_init(); + else if(random(100)<5&&self.t_width 20 ) + { + self.z_movement = random(-2,0); + self.z_duration = time + HX_FRAME_TIME * random(15,25); + } + + if (self.monster_duration <= 0) + { + chance = random(); + if (chance < .33) + { + self.monster_stage = FANGEL_STAGE_FLOAT; + self.monster_duration = random(10,30); + } + else if (chance < .66) + self.think = fangel_handframes; // Come back fighting + else + self.think = fangel_wingframes; // Come back fighting + } +} + +void fangel_fly (float thrust) +{ +float retval; +float dist; +float Length; + + Length = vhlen(self.origin - self.monster_last_seen); + self.ideal_yaw = vectoyaw(self.monster_last_seen - self.origin); + ChangeYaw(); + + dist = (2.0 + thrust * 4); // Movement distance this turn + + if (Length < 20) + { + if (random() < 0.1) + fangel_find_spot(); + else + { + self.monster_stage = FANGEL_STAGE_FLOAT; + self.monster_duration = random(10,30); + } + return; + } + + retval = walkmove(self.angles_y, dist, FALSE); + + if (!retval) + { + fangel_find_spot(); + return; + } + + dist = self.origin_z - self.monster_last_seen_z; + + if (dist < -20) + { + self.z_movement = random(2,4); + self.z_duration = time + HX_FRAME_TIME * random(15,25); + } + else if (dist > 20) + { + self.z_movement = random(-2,-4); + self.z_duration = time + HX_FRAME_TIME * random(15,25); + } + + if (self.z_duration > time) + movestep(0,0,self.z_movement, FALSE); +} + +void () fangel_float = +{ + self.monster_duration = self.monster_duration - 1; + ai_face(); + + enemy_range = range (self.enemy); // Attack if they are too near + if ((enemy_range <= RANGE_NEAR) && (random() < .25)) + self.monster_duration = 0; + else if ((enemy_range <= RANGE_MELEE) && (random() < .90)) + self.monster_duration = 0; + + if (self.monster_duration <= 0) + { + self.monster_stage = FANGEL_STAGE_FLY; + fangel_find_spot(); + } +}; + + +void fangel_move (float thrust) +{ + check_z_move(thrust/2); +// movestep(0,0,thrust/2, FALSE); + + if (self.monster_stage == FANGEL_STAGE_WAIT) + { + dprint("Waiting\n"); + fangel_wait(); + return; + } + else if (self.monster_stage == FANGEL_STAGE_FLY) + { + fangel_fly(thrust); + return; + } + else if (self.monster_stage == FANGEL_STAGE_SIDESTEP) + { + fangel_sidestep(); + return; + } + else if (self.monster_stage == FANGEL_STAGE_FLOAT) + { + fangel_float(); + return; + } +} + +void () fangel_prepare_attack = +{ + ai_face(); +}; + +void () fangel_hand_fire = +{ + fangel_prepare_attack(); + + sound (self, CHAN_WEAPON, "fangel/hand.wav", 1, ATTN_NORM); + + do_faSpell('10 -4 8',400); + do_faSpell('10 -4 8',300); +}; + +void () fangel_wing_fire = +{ + fangel_prepare_attack(); + + sound (self, CHAN_WEAPON, "fangel/wing.wav", 1, ATTN_NORM); + + makevectors (self.angles); + + do_faBlade('8 6 4',360, v_right*2); + do_faBlade('-8 6 4',360, v_right*(-2)); +}; + + +float fangel_fly_offsets[20] = +{ + 0, + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.8, + 0.9, + 1, + 0.9, + 0.8, + 0.7, + 0.6, + 0.5, + 0.4, + 0.3, + 0.2, + 0.1 +}; + +// Frame Code + +void() fangel_blockframes = +{ +float RetVal; +float chance; + self.think = fangel_blockframes; + thinktime self : HX_FRAME_TIME; + + if(self.velocity!='0 0 0') + self.velocity=self.velocity*0.7; + + // Turn to face the attacker + ai_face(); + + check_z_move(3); +// movestep(0,0,-1, FALSE); // Float down while deflecting shots + + + + if (self.fangel_Count) + { + self.fangel_Count -= 1; + RetVal = 3; + } + else if(fov(self,self.enemy,30)&&self.enemy.last_attack+0.75>time&&self.frame == $fblock13) + self.fangel_Count+=1; + else + RetVal = AdvanceFrame($fblock1,$fblock21); + + if (self.frame==$fblock21) // Only deflect after this frame + { + if(self.movechain) + remove(self.movechain); + self.movechain=world; + } + + if (RetVal == AF_END) + { + self.takedamage = DAMAGE_YES; + chance = random(); + + if (chance < .1) + self.think = self.th_save; + else if (chance < .60) + self.think = fangel_handframes; // Come back fighting + else + self.think = fangel_wingframes; // Come back fighting + + } + else if (RetVal == AF_NORMAL) + { + if (self.frame == $fblock13) + self.fangel_Count = 40; + } + + if (self.frame == $fblock9) + { + self.takedamage = DAMAGE_NO; + spawn_reflect(); + } +}; + +void() fangel_deathframes = +{ +entity stemp;//,skull; + + if(self.health<=-40) + { + chunk_death(); + return; + } + + self.think = fangel_deathframes; + thinktime self : HX_FRAME_TIME; + + traceline (self.origin, self.origin - '0 0 250',FALSE,self); + particle2(trace_endpos,'-30 -30 50','30 30 100',384,PARTICLETYPE_SPELL,80); + + if (self.frame == 26) + self.drop_time = time + .25; + + if ((self.frame == 27) && (!self.flags & FL_ONGROUND)) + { + self.frame = 26; + self.velocity_z = -20; + if (self.drop_time < time) // Dropping too long so let her die. + self.frame = 27; + } + +/*Should she spew a head if not chunked? + if (self.frame == $fdeth40) + { + skull= spawn(); + CreateEntityNew(skull,ENT_FANGEL_HEAD,"models/h_fangel.mdl",chunk_death); + + skull.flags(-)FL_ONGROUND; + + skull.avelocity_x = random(30); + skull.avelocity_y = random(30); + skull.avelocity_z = random(80); + thinktime skull : random(4,10); + skull.think = MakeSolidCorpse; + setorigin(skull,self.origin); + } +*/ + + if (AdvanceFrame($fdeth1,$fdeth40) == AF_BEGINNING) + remove(self); + + if (self.frame == $fdeth1) + self.movetype = MOVETYPE_STEP; + + if (self.frame == $fdeth10) + { + if (self.classname == "monster_fallen_angel") + sound (self, CHAN_WEAPON, "fangel/death.wav", 1, ATTN_NORM); + else + sound (self, CHAN_WEAPON, "fangel/death2.wav", 1, ATTN_NORM); + } +}; + + +void fangel_flyforward (void) +{ + AdvanceFrame($fmove1,$fmove20); + self.frame += 1; + + fangel_move(3*fangel_fly_offsets[self.frame - $fmove1]); + + if (self.frame == $fmove2) + sound (self, CHAN_WEAPON, "fangel/fly.wav", 1, ATTN_NORM); + + if ((self.frame >= $fmove6 && self.frame <= $fmove8) || + (self.frame >= $fmove16 && self.frame <= $fmove18)) + { + self.fangel_SaveFrame = self.frame; + fangel_check_wing(); + } +} + +void fangel_flyother (void) +{ + AdvanceFrame($ffly1,$ffly30); + fangel_move(3*fangel_fly_offsets[rint((self.frame - $ffly1)*.65)]); + + if (self.frame == $ffly1) + sound (self, CHAN_WEAPON, "fangel/fly.wav", 1, ATTN_NORM); + + if ((self.frame >= $ffly11 && self.frame <= $ffly13) || + (self.frame >= $ffly26 && self.frame <= $ffly28)) + { + self.fangel_SaveFrame = self.frame; + fangel_check_wing(); + } +} + +void() fangel_flyframes = +{ + self.think = fangel_flyframes; + thinktime self : HX_FRAME_TIME; + + fangel_check_incoming(); + + if(self.velocity!='0 0 0') + self.velocity=self.velocity*0.7; + + if (self.monster_stage == FANGEL_STAGE_FLY) + fangel_flyforward(); + else + fangel_flyother(); +}; + +void fangel_handframes (void) +{ + self.think = fangel_handframes; + thinktime self : HX_FRAME_TIME; + + fangel_check_incoming(); + + if (AdvanceFrame($fhand1,$fhand22) == AF_END) + { + fangel_prepare_attack(); + + if (random() < .25) + { + self.monster_stage = FANGEL_STAGE_SIDESTEP; + self.monster_duration = random(20,40); + fangel_find_spot(); + self.think = fangel_flyframes; + } + else + { + self.think = self.th_save; + } + + self.frame = self.fangel_SaveFrame; + self.yaw_speed = fangel_move_speed; + } + else + { + if (self.frame == $fhand12) fangel_hand_fire(); + else fangel_prepare_attack(); + } +} + +void() fangel_painframes = +{ + float chance; + + self.think = fangel_painframes; + thinktime self : HX_FRAME_TIME; + + if (AdvanceFrame($fpain1,$fpain12) == AF_END) + { + fangel_check_incoming(); + + chance = random(); + if (chance < .33) + self.think = self.th_save; + else if (chance < .66) + self.think = fangel_handframes; // Come back fighting + else + self.think = fangel_wingframes; // Come back fighting + + self.frame = self.fangel_SaveFrame; + } +}; + +void() fangel_wingframes = +{ + self.think = fangel_wingframes; + thinktime self : HX_FRAME_TIME; + + if (AdvanceFrame($fwing1,$fwing30) == AF_END) + { + fangel_prepare_attack(); + + if (random() < .25) + { + self.monster_stage = FANGEL_STAGE_SIDESTEP; + self.monster_duration = random(20,40); + fangel_find_spot(); + self.think = fangel_flyframes; + } + else + self.think = self.th_save; + + self.frame = self.fangel_SaveFrame; + self.yaw_speed = fangel_move_speed; + } + else + { + if (self.classname == "monster_fallen_angel") + { + if (self.frame == $fwing21) + { + if (self.shoot_cnt < 3) + { + if (self.shoot_time < time) + { + fangel_wing_fire(); + self.shoot_cnt += 1; + self.shoot_time = time + HX_FRAME_TIME * 3; + } + self.frame = $fwing20; + } + else + self.shoot_cnt =0; + } + else + fangel_prepare_attack(); + } + else + { + if (self.frame == $fwing21) + { + if (self.shoot_cnt < 10) + { + vector org; + org=self.origin-'0 0 5'; + traceline(org,(self.enemy.absmin+self.enemy.absmax)*0.5,TRUE,self); + if (trace_fraction==1) + { + self.effects(+)EF_MUZZLEFLASH; + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_STREAM_COLORBEAM); //beam type + WriteEntity (MSG_BROADCAST, self); //owner + WriteByte (MSG_BROADCAST, 0); //tag + flags + WriteByte (MSG_BROADCAST, 1); //time + WriteByte (MSG_BROADCAST, rint(random(0,4))); //color + + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + + WriteCoord (MSG_BROADCAST, trace_endpos_x); + WriteCoord (MSG_BROADCAST, trace_endpos_y); + WriteCoord (MSG_BROADCAST, trace_endpos_z); + + LightningDamage (self.origin, trace_endpos, self, 3,"sunbeam"); + + self.frame -= 1; + self.shoot_cnt += 1; + } + self.frame = $fwing20; + } + else + self.shoot_cnt =0; + + } + else + fangel_prepare_attack(); + } + } +}; + +void(entity attacker, float damage) fangel_pain = +{ + if (random(self.health) > damage||self.pain_finished>time) + return; // didn't flinch + + self.pain_finished=time + 1 + self.skin; + + if (self.health < 50) + self.drawflags (-) DRF_TRANSLUCENT|MLS_POWERMODE; + + if ((self.frame >= $ffly11 && self.frame <= $ffly13) || + (self.frame >= $ffly26 && self.frame <= $ffly28)) + { + if (self.classname == "monster_fallen_angel") + sound (self, CHAN_WEAPON, "fangel/pain.wav", 1, ATTN_NORM); + else + sound (self, CHAN_WEAPON, "fangel/pain2.wav", 1, ATTN_NORM); + + self.fangel_SaveFrame = self.frame; + // didn't want to use self.think just in case we just began to attack + self.th_save = fangel_flyframes; + fangel_painframes(); + } +}; + + +void() init_fangel = +{ + if (deathmatch) + { + remove(self); + return; + } + + self.monster_stage = FANGEL_STAGE_WAIT; + + precache_model2 ("models/fangel.mdl"); + precache_model2 ("models/faspell.mdl"); + precache_model2 ("models/fablade.mdl"); + precache_model2 ("models/h_fangel.mdl"); + + precache_sound2("fangel/fly.wav"); + precache_sound2("fangel/deflect.wav"); + precache_sound2("fangel/hand.wav"); + precache_sound2("fangel/wing.wav"); + + CreateEntityNew(self,ENT_FANGEL,"models/fangel.mdl",fangel_deathframes); + + self.skin = 0; + + self.hull = HULL_BIG; + if (self.classname == "monster_fallen_angel") + { + precache_sound2("fangel/ambi1.wav"); + self.skin = 0; + self.health = 250; + self.experience_value = 150; + } + else + { + precache_sound2("fangel/ambi2.wav"); + self.skin = 1; + self.health = 500; + self.experience_value = 400; + } + + self.th_stand = fangel_flyframes; + self.th_walk = fangel_flyframes; + self.th_run = fangel_flyframes; + self.th_pain = fangel_pain; + self.th_die = fangel_deathframes; + self.th_missile = fangel_handframes; + self.th_melee = fangel_wingframes; + self.headmodel="models/h_fangel.mdl"; + + total_monsters += 1; + + self.ideal_yaw = self.angles * '0 1 0'; + self.yaw_speed = fangel_move_speed; + self.view_ofs = '0 0 -5'; + self.use = monster_use; + self.mintel = 3; + + self.flags (+) FL_FLY | FL_MONSTER; + self.flags2 (+) FL_ALIVE; + + if (self.classname == "monster_fallen_angel_lord") + self.drawflags (+) DRF_TRANSLUCENT; + + self.pausetime = 99999999; + self.frame=$fhand1; + self.think=fangel_wait; + thinktime self : 0; +// self.th_stand (); +}; + + +/*QUAKED monster_fallen_angel (1 0.3 0) (-14 -14 -41) (14 14 23) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +New item for QuakeEd + +-------------------------FIELDS------------------------- +-------------------------------------------------------- + +*/ +void() monster_fallen_angel = +{ + precache_sound2("fangel/death.wav"); + precache_sound2("fangel/pain.wav"); + + init_fangel(); +}; + +/*QUAKED monster_fallen_angel_lord (1 0.3 0) (-14 -14 -41) (14 14 23) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +New item for QuakeEd + +-------------------------FIELDS------------------------- +-------------------------------------------------------- + +*/ +void() monster_fallen_angel_lord = +{ + precache_sound2("fangel/death2.wav"); + precache_sound2("fangel/pain2.wav"); + + init_fangel(); +}; + diff --git a/faspell.hc b/faspell.hc new file mode 100644 index 0000000..d794047 --- /dev/null +++ b/faspell.hc @@ -0,0 +1,141 @@ +/* + * $Header: /HexenWorld/Siege/FAspell.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\Fangel\spell\FAspell.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\Fangel\spell +$origin 0 0 0 +$base BASE skin1 +$skin skin1 +$flags 0 + +// +$frame SPELL01 SPELL02 SPELL03 SPELL04 SPELL05 +$frame SPELL06 SPELL07 SPELL08 SPELL09 + + + +void() faSpellTouch = +{ +float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + damg = random(12,22); + + if (other.health) + T_Damage (other, self, self.owner, damg ); + + T_RadiusDamage (self, self.owner, damg, other); + + sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + + self.origin = self.origin - 8*normalize(self.velocity); + CreateRedSpark(self.origin); + remove(self); +}; + +// Frame Code +/* +void() frame_SPELL01 = [ $SPELL01 , frame_SPELL02 ] { }; +void() frame_SPELL02 = [ $SPELL02 , frame_SPELL03 ] { }; +void() frame_SPELL03 = [ $SPELL03 , frame_SPELL04 ] { }; +void() frame_SPELL04 = [ $SPELL04 , frame_SPELL05 ] { }; +void() frame_SPELL05 = [ $SPELL05 , frame_SPELL06 ] { }; +void() frame_SPELL06 = [ $SPELL06 , frame_SPELL07 ] { }; +void() frame_SPELL07 = [ $SPELL07 , frame_SPELL08 ] { }; +void() frame_SPELL08 = [ $SPELL08 , frame_SPELL09 ] { }; +void() frame_SPELL09 = [ $SPELL09 , frame_SPELL01 ] { }; +*/ + + +void() faspell_frames = +{ + float old_angle, old_count; + vector new_posA, new_posB, posA, posB; + + self.think = faspell_frames; + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($SPELL01,$SPELL09); + AdvanceFrame($SPELL01,$SPELL09); + + old_angle = self.spell_angle; + old_count = self.count; + self.spell_angle += random(32,42); + if (self.spell_angle >= 360) self.spell_angle -= 360; + if (self.count < 6) + self.count += 0.6; + + makevectors (self.angles); + + posA = v_right * sin(self.spell_angle) * self.count; + posB = v_right * sin(old_angle) * old_count; + new_posA = (posA-posB); + posA = v_up * cos(self.spell_angle) * self.count; + posB = v_up * cos(old_angle) * old_count; + new_posB = (posA-posB); + new_posA += new_posB; + movestep(new_posA_x,new_posA_y,new_posA_z, FALSE); + + if(self.lifetime=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, FALSE, trace_ent); + + if (trace_ent != targ) + if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + return FALSE;//Don't have a clear shot, and don't want to shoot obstruction + +//FIXME: check for translucent water? + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (enemy_range == RANGE_MELEE) + { // melee attack + if (self.th_melee) + { + self.th_melee (); + return TRUE; + } + } + +//FIXME: check for darkness, maybe won't fire, maybe aim will be off + +// missile attack + if (!self.th_missile) + return FALSE; + + if (time < self.attack_finished) + return FALSE; + + if (enemy_range == RANGE_FAR) + return FALSE; + + if (enemy_range == RANGE_MELEE) + { + chance = 0.9; + self.attack_finished = 0; + } + else if (enemy_range == RANGE_NEAR) + { + if (self.th_melee) + chance = 0.2; + else + chance = 0.4; + } + else if (enemy_range == RANGE_MID) + { + if (self.th_melee) + chance = 0.05; + else + chance = 0.1; + } + else + chance = 0; + + if (random () < chance) + { + self.th_missile (); + SUB_AttackFinished (random(0,2)); + return TRUE; + } + + return FALSE; +} + + +/* + * ai_face() -- Keep facing the enemy. + */ + +void ai_face() +{ + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); +// self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + ChangeYaw(); +} + + +/* + * ai_charge() -- The monster is in a melee attack, so get as close as + * possible to .enemy. + */ + +float visible(entity targ); +float infront(entity targ); +float range (entity targ); + +void ai_charge(float d) +{ + ai_face(); + movetogoal(d); // done in C code... +} + +void ai_charge_side() +{ + local vector dtemp; + local float heading; + +// aim to the left of the enemy for a flyby + +// self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + ChangeYaw(); + + makevectors (self.angles); + dtemp = self.enemy.origin - 30*v_right; + heading = vectoyaw(dtemp - self.origin); + + walkmove(heading, 20, FALSE); +} + + +/* + * ai_melee() + */ + +void ai_melee() +{//Bad idea- doesn't care where around self player is! +vector org1,org2; +float ldmg; + + if (!self.enemy) + return; // removed before stroke + + org1=self.origin+self.proj_ofs; + org2=self.enemy.origin; + + if(vlen(org2-org1)>60) + return; + + traceline(org1,org2,FALSE,self); + if(trace_ent!=self.enemy) + { + org2=(self.enemy.absmin+self.enemy.absmax)*0.5; + traceline(org1,org2,FALSE,self); + } + + if(!trace_ent.takedamage) + return; + + if(self.model=="models/spider.mdl") + ldmg=random(self.scale*3); + else + ldmg = random(9); + + T_Damage (trace_ent, self, self, ldmg); +} + + +/* + * ai_melee_side() + */ + +void ai_melee_side() +{ + local vector delta; + local float ldmg; + + if (!self.enemy) + return; // removed before stroke + + ai_charge_side(); + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 60) + return; + if (!CanDamage (self.enemy, self)) + return; + ldmg = random(9); + T_Damage (self.enemy, self, self, ldmg); +} + diff --git a/fireball.hc b/fireball.hc new file mode 100644 index 0000000..011f781 --- /dev/null +++ b/fireball.hc @@ -0,0 +1,144 @@ +/* + * $Header: /HexenWorld/Siege/fireball.hc 3 5/25/98 1:38p Mgummelt $ + */ +/* +============================================================================== + +FIREBALL + +============================================================================== +*/ + +// For building the model +$cd c:\model\fireball // Directory to find model in +$origin 0 0 0 +// baseframe is in iceimp.3ds +$base fireball +// skin is in iceimp.lbm +$skin fireball + +// Imp throwing +$frame firbal1 firbal2 firbal3 firbal4 firbal5 +$frame firbal6 firbal7 firbal8 firbal9 firbal10 + + +//============================================================================ +void FireFizzle (void) +{ + sound (self, CHAN_WEAPON, "misc/fout.wav", 1, ATTN_NORM); + DeathBubbles(1); + remove(self); +} + +void() fireballTouch = +{ + local float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + if (self.dmg == -1) + damg = random(5,10); + else if (self.dmg) + damg = self.dmg; + else + damg = random(12,22); + + if (other.health) + { + if (self.owner.classname == "cube_of_force") + T_Damage (other, self.owner, self.owner.owner, damg ); + else + T_Damage (other, self, self.owner, damg ); + } + + // don't do radius damage to the other, because all the damage + // was done in the impact + T_RadiusDamage (self, self.owner, damg, other); + +// sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + self.origin = self.origin - 8*normalize(self.velocity); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_EXPLOSION); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + + remove(self); +// BecomeExplosion (); +}; + + + + + +//============================================================================ + + +void fireball_1(void) +{ + float retval; + + self.nextthink = time + HX_FRAME_TIME; + + retval = AdvanceFrame($firbal1,$firbal10); + + if (retval == AF_BEGINNING) + { + if (pointcontents(self.origin) != CONTENT_EMPTY) + FireFizzle(); + } +} + +//============================================================================ + + +void(vector offset) do_fireball = +{ +entity missile; +vector vec; + + missile = spawn (); + missile.owner = self; + missile.speed=500; + if(self.classname=="monster_imp_lord") + { + missile.dmg=random(80,120); + missile.speed+=500; + missile.scale=2; + } + else + missile.dmg = self.dmg; + + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.health = 10; + + setmodel (missile, "models/fireball.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + +// set missile speed + + makevectors (self.angles); + vec = self.origin + self.view_ofs + v_factor(offset); + setorigin (missile, vec); + + vec = self.enemy.origin - missile.origin + self.enemy.view_ofs; + vec = normalize(vec); + + missile.velocity = (vec+aim_adjust(self.enemy))*missile.speed; + missile.angles = vectoangles('0 0 0'-missile.velocity); + + missile.touch = fireballTouch; + + missile.think = fireball_1; + missile.nextthink = time + HX_FRAME_TIME; +}; + diff --git a/fish.hc b/fish.hc new file mode 100644 index 0000000..00b670e --- /dev/null +++ b/fish.hc @@ -0,0 +1,552 @@ +/* + * $Header: /HexenWorld/Siege/Fish.hc 9 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\FISH\FISH1.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\FISH +$origin 0 0 0 +$base BASE SKIN +$skin SKIN +$skin SKIN2 +$flags 0 + +// +$frame SWIM01 SWIM02 SWIM03 SWIM04 SWIM05 +$frame SWIM06 SWIM07 SWIM08 SWIM09 SWIM10 +$frame SWIM11 SWIM12 SWIM13 SWIM14 SWIM15 +$frame SWIM16 SWIM17 SWIM18 SWIM19 SWIM20 +$frame SWIM21 SWIM22 SWIM23 SWIM24 SWIM25 +$frame SWIM26 SWIM27 SWIM28 SWIM29 SWIM30 +$frame SWIM31 SWIM32 SWIM33 SWIM34 SWIM35 +$frame SWIM36 SWIM37 SWIM38 SWIM39 SWIM40 + + + + +// Frame Code +float FISH_STAGE_MOVE = 1; +float FISH_STAGE_FOLLOW = 2; +float FISH_STAGE_BORED = 3; + +void fish_hover(void); +void fish_move(void); + + +float fish_friends(void) +{ + entity item,test; + float bad; + + item = findradius(self.origin, 100); + while (item) + { + if (item.classname == "monster_fish" && item != self) + { + test = item.goalentity; + bad = FALSE; + while(test != world && bad != TRUE) + { + if (test == self) bad = TRUE; + + test = test.goalentity; + } + if (!bad) + { + self.goalentity = item; + self.goalentity.fish_leader_count += 1; + return TRUE; + } + } + item = item.chain; + } + + return FALSE; +} + +void fish_follow(void) +{ + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($SWIM01,$SWIM40); + + if (random() > 0.1) + return; + + if (random() < .05) + { + self.monster_duration = random(250,450); + self.monster_stage = FISH_STAGE_BORED; + self.think = fish_hover; + self.goalentity.fish_leader_count -= 1; + self.goalentity = world; + //dprint("Fish got bored\n"); +// self.drawflags (-) MLS_ABSLIGHT; + } + + self.movedir = self.monster_last_seen - self.origin + randomv('-20 -20 -25', '20 20 25'); + if (self.goalentity.goalentity) + { + self.goalentity.fish_leader_count -= 1; + self.goalentity = self.goalentity.goalentity; + self.goalentity.fish_leader_count += 1; + } + + self.monster_last_seen = self.goalentity.origin; + + self.count = 80 + random(20); + self.movedir_x /= self.count; + self.movedir_y /= self.count; + self.movedir_z /= self.count; + self.fish_speed = vhlen(self.movedir); + + self.think = fish_move; +} + +void fish_move(void) +{ + float retval; + + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($SWIM01,$SWIM40); + + self.ideal_yaw = vectoyaw(self.movedir); + ChangeYaw(); + retval = walkmove(self.angles_y, self.fish_speed, FALSE); + retval = movestep(0, 0, self.movedir_z, FALSE); + +/* if (retval != 2) + { + self.goalentity = world; + self.monster_stage = FISH_STAGE_MOVE; + } +*/ + if (self.count >= 170) + self.fish_speed *= 1.05; + else if (self.count < 30) + self.fish_speed *= .9; + + self.count -= 1; + + + if (self.count < 1) + { + self.count = 0; + if (self.monster_stage == FISH_STAGE_MOVE) + { + if (fish_friends()) + { + self.monster_stage = FISH_STAGE_FOLLOW; + self.think = fish_follow; + self.monster_last_seen = self.goalentity.origin; + //self.drawflags (+) MLS_ABSLIGHT; + //self.abslight = 0; + //self.goalentity.drawflags (+) MLS_ABSLIGHT; + //self.goalentity.abslight = 2.5; + //dprint("Following!\n"); + } + else + self.think = fish_hover; + } + else if (self.monster_stage == FISH_STAGE_FOLLOW) + self.think = fish_follow; + else if (self.monster_stage == FISH_STAGE_BORED) + self.think = fish_hover; + } +} + +void fish_hover(void) +{ + float try; + + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($SWIM01,$SWIM40); + + if (self.monster_stage == FISH_STAGE_BORED) + { + self.monster_duration -= 1; + if (self.monster_duration <= 0) + self.monster_stage = FISH_STAGE_MOVE; + } + + if (random() < 0.02) + { + try = 0; + while (try < 10) + { + self.movedir = randomv('-100 -100 -30', '100 100 30'); + tracearea(self.origin, self.origin + self.movedir, self.mins, self.maxs, FALSE, self); + if (trace_fraction == 1) + { + self.think = fish_move; + + self.count = 170 + random(30); + self.movedir_x /= 400; + self.movedir_y /= 400; + self.movedir_z /= 400; + self.fish_speed = vhlen(self.movedir); + try = 999; + } + try += 1; + } + } +} + +void fish_die(void) +{ + remove(self); +} + +/*QUAKED monster_fish (1 0 0) (-16 -16 -8) (16 16 8) +Ambient Fish + +-------------------------FIELDS------------------------- +skin: 0 = bright colored, 1 = darker colored +-------------------------------------------------------- + +*/ +void monster_fish(void) +{ + precache_model2 ("models/fish.mdl"); + + self.takedamage = DAMAGE_YES; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_FLY; + self.flags (+) FL_SWIM | FL_MONSTER; + self.yaw_speed = 2; + self.hull = HULL_PLAYER; + self.monster_stage = FISH_STAGE_MOVE; + self.mass = 99999; // Big fishies! + +// self.drawflags (+) MLS_POWERMODE; + + setmodel (self, "models/fish.mdl"); + self.skin = 0; + + setsize (self, '-10 -10 -8', '10 10 8'); + self.health = 1; + + self.th_die = fish_die; + self.think = fish_hover; + thinktime self : HX_FRAME_TIME; +} + +//SIEGE PIRHANA +void() swimmonster_start_go = +{ +// if(!self.touch) +// self.touch=obj_push; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + + if(self.view_ofs=='0 0 0'); + self.view_ofs = '0 0 2'; + if(self.proj_ofs=='0 0 0'); + self.proj_ofs = '0 0 2'; + + self.use = monster_use; + + self.flags(+)FL_MONSTER; + + if (self.target) + { + self.goalentity = self.pathentity = find(world, targetname, self.target); + if (!self.pathentity) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + +// spread think times so they don't all happen at same time + self.nextthink+=random(0.5); +}; + +void() swimmonster_start = +{ +// spread think times so they don't all happen at same time + self.takedamage=DAMAGE_YES; + self.nextthink+=random(0.5); + self.think = swimmonster_start_go; + total_monsters = total_monsters + 1; + self.monster_awake=TRUE; +}; + +void()fish_melee; +void pirhana_flop_back () +{ + if(pointcontents(self.origin)==CONTENT_WATER) + { + self.avelocity='0 0 0'; + self.movetype=MOVETYPE_SWIM; + self.angles_x=self.angles_z=0; + self.think = self.th_stand; + thinktime self : 0; + return; + } + if(self.cnt>3) + { + self.cnt=0; + setorigin(self,self.init_org); + self.think=pirhana_flop_back; + thinktime self: 0.5; + } + else + { + self.cnt+=1; + self.velocity=normalize(self.wallspot - self.origin); + self.velocity=self.velocity*400; + self.velocity_z=270; + self.avelocity=self.velocity*random(-3,3); + self.flags(-)FL_ONGROUND; + self.think=pirhana_flop_back; + thinktime self: 2; + } +} + +void pirhana_throw () +{ + self.wallspot=self.origin; + self.velocity=normalize(self.enemy.origin+(random(self.enemy.maxs_z)*'0 0 1')-self.origin); + self.angles=vectoangles(self.velocity); + self.velocity=self.velocity*400+' 0 0 200'; + self.movetype=MOVETYPE_BOUNCE; + self.flags(-)FL_ONGROUND; + self.touch=fish_melee; + self.think=pirhana_flop_back; + thinktime self: 2; +} + +void pirhana_check_enemy () +{ + if(pointcontents(self.enemy.origin)==CONTENT_WATER) + self.search_time=time+5; + + if(self.enemy.health<=0||self.enemy.rings & RING_WATER||self.search_time0) + return; + + found=nextent(world); + while(found!=world) + { + if(pointcontents(found.origin)==CONTENT_WATER&& + found.takedamage&& + found.classname!=self.classname&& + found.thingtype==THINGTYPE_FLESH&& + (!found.rings & RING_WATER)) + { + self.monster_awake=TRUE; + self.enemy=self.goalentity=found; + found=world; + self.think=self.th_run; + thinktime self : 0; + } + else + found=nextent(found); + } +} + +void fish_run () //[++0 .. 39 ] +{ + self.think=fish_run; + thinktime self: 0.05; + if(self.velocity_x||self.velocity_y||self.velocity_z) + self.velocity=self.velocity*0.75; + + pirhana_check_enemy(); + if(!self.enemy) + { + if(self.pathentity) + self.think=self.th_walk; + else + self.think=self.th_stand; + thinktime self : 0; + return; + } + ai_run(self.speed*0.75); + if(random()<0.05) + pirhana_hunt(); +} + +void fish_walk () //[++0 .. 39 ] +{ + self.think=fish_walk; + thinktime self: 0.05; + if(self.velocity_x||self.velocity_y||self.velocity_z) + self.velocity=self.velocity*0.75; + + pirhana_check_enemy(); + ai_walk(self.speed/3); + if(random()<0.05) + pirhana_hunt(); +} + +void fish_stand () //[++0 .. 39 ] +{ + self.think=fish_stand; + thinktime self: 0.05; + if(self.velocity_x||self.velocity_y||self.velocity_z) + self.velocity=self.velocity*0.75; + + pirhana_check_enemy(); + + ai_stand(); + if(random()<0.05) + pirhana_hunt(); +} + +void fish_melee () +{ +vector delta,hitspot; +float ldmg; + + if(self.attack_finished>time) + return; + + if (!self.enemy) + return; // removed before bite + + hitspot = self.enemy.origin+(random(self.enemy.maxs_z))*'0 0 1'; + delta = hitspot- self.origin; + + if (vlen(delta) > 60) + return; + + if(random()<0.3) + sound (self.enemy, CHAN_ITEM, "spider/bite.wav", 1, ATTN_NORM); + ldmg = (random() + random()) * 3; + if(self.enemy.health<=ldmg) + ldmg=100; + T_Damage (self.enemy, self, self, ldmg); + MeatChunks (hitspot,randomv('-200 -200 0','200 200 400'), 3,self.enemy); + SpawnPuff (hitspot, '0 0 0', 3,self.enemy); + + if(self.movetype==MOVETYPE_BOUNCE) + self.attack_finished=time + 1; +} + +void fish_attack()// [++0 .. 39 ] +{ + self.think=fish_attack; + thinktime self: 0.05; + if(self.velocity_x||self.velocity_y||self.velocity_z) + self.velocity=self.velocity*0.75; + + pirhana_check_enemy(); +/* + if(pointcontents(self.enemy.origin)!=CONTENT_WATER) + { + if(vlen(self.enemy.origin-self.origin)<128) + if(random()<0.05) + { + self.flags(+)FL_FLY; + self.flags(-)FL_SWIM; + } + if(self.flags&FL_SWIM) + self.enemy=world; + } +*/ + if(!self.enemy) + { + if(self.pathentity) + self.think=self.th_walk; + else + self.think=self.th_stand; + thinktime self : 0; + return; + } + ai_charge(self.speed); + if(random()<0.3) + fish_melee(); +} + +/*QUAKED monster_pirhana (1 0 0) (-16 -16 0) (16 16 28) +*/ +void() monster_pirhana = +{ + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + precache_model ("models/fish.mdl"); + precache_sound ("spider/bite.wav"); + + setmodel (self,"models/fish.mdl"); + + setsize (self, '0 0 0', '0 0 0'); + // setsize (self, '-4 -4 -4', '4 4 4'); + self.hull=HULL_POINT;//use pentacles + self.health=10000000; + self.init_org=self.origin; +/* + if(skill==3) + self.health = 800; + else + self.health = 400; +*/ + self.mass = 0.1; + self.speed=14+random(6); + + self.thingtype=THINGTYPE_FLESH; + self.th_stand = fish_stand; + self.th_walk = fish_walk; + self.th_run = fish_run; + self.th_die = chunk_death; + self.th_melee = fish_attack; +// self.flags2(+)FL_ALIVE; + self.flags(+)FL_SWIM; + + swimmonster_start (); +}; + diff --git a/flag.hc b/flag.hc new file mode 100644 index 0000000..7054451 --- /dev/null +++ b/flag.hc @@ -0,0 +1,15 @@ +/* + * $Header: /HexenWorld/Siege/Flag.hc 3 5/25/98 1:38p Mgummelt $ + */ +/*QUAKED item_deathball (.3 .3 1) (0 0 0) (32 32 32) +-----------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() deathball_touch; + +void() item_deathball = +{ + self.touch = deathball_touch; +}; + diff --git a/flameorb.hc b/flameorb.hc new file mode 100644 index 0000000..9d9d51a --- /dev/null +++ b/flameorb.hc @@ -0,0 +1,782 @@ +/* +============================================================================== + +Q:\art\models\weapons\spllbook\spllbook.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\spllbook +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame idlebn01 idlebn02 idlebn03 idlebn04 idlebn05 +$frame idlebn06 idlebn07 idlebn08 idlebn09 idlebn10 +$frame idlebn11 idlebn12 idlebn13 idlebn14 idlebn15 +$frame idlebn16 idlebn17 idlebn18 idlebn19 idlebn20 +$frame idlebn21 idlebn22 idlebn23 idlebn24 idlebn25 + +// +$frame idlean26 idlean27 idlean28 idlean29 idlean30 +$frame idlean31 idlean32 idlean33 idlean34 idlean35 +$frame idlean36 idlean37 idlean38 idlean39 idlean40 +$frame idlean41 idlean42 idlean43 idlean44 idlean45 +$frame idlean46 idlean47 idlean48 idlean49 idlean50 + +// +$frame normal51 normal52 normal53 normal54 normal55 +$frame normal56 normal57 normal58 normal59 normal60 +$frame normal61 normal62 normal63 normal64 + +// +$frame topowr65 topowr66 topowr67 topowr68 topowr69 +$frame topowr70 topowr71 topowr72 topowr73 topowr74 +$frame topowr75 topowr76 topowr77 topowr78 topowr79 +$frame topowr80 topowr81 topowr82 topowr83 topowr84 + +// +$frame pidleb085 pidleb086 pidleb087 pidleb088 pidleb089 +$frame pidleb090 pidleb091 pidleb092 pidleb093 pidleb094 +$frame pidleb095 pidleb096 pidleb097 pidleb098 pidleb099 +$frame pidleb100 pidleb101 pidleb102 pidleb103 pidleb104 +$frame pidleb105 pidleb106 pidleb107 pidleb108 pidleb109 + +// +$frame pidlea110 pidlea111 pidlea112 pidlea113 pidlea114 +$frame pidlea115 pidlea116 pidlea117 pidlea118 pidlea119 +$frame pidlea120 pidlea121 pidlea122 pidlea123 pidlea124 +$frame pidlea125 pidlea126 pidlea127 pidlea128 pidlea129 +$frame pidlea130 pidlea131 pidlea132 pidlea133 pidlea134 + +// +$frame powern135 powern136 powern137 powern138 powern139 +$frame powern140 powern141 powern142 powern143 powern144 +$frame powern145 powern146 powern147 powern148 + +// +$frame tonrml149 tonrml150 tonrml151 tonrml152 tonrml153 +$frame tonrml154 tonrml155 tonrml156 tonrml157 tonrml158 +$frame tonrml159 tonrml160 tonrml161 tonrml162 tonrml163 +$frame tonrml164 tonrml165 tonrml166 tonrml167 tonrml168 + +// +$frame ndesel213 ndesel214 ndesel215 ndesel216 ndesel217 +$frame ndesel218 ndesel219 ndesel220 ndesel221 ndesel222 +$frame ndesel223 + +// +$frame pselon224 pselon225 pselon226 pselon227 pselon228 +$frame pselon229 pselon230 pselon231 pselon232 pselon233 +$frame pselon234 + +/* +void burner_think () +{ + if(self.lifetime0) + smolder(other_org); + + } + else + { + T_RadiusDamage(self,self.owner,40,self.owner); + } + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_FIREWALL_IMPACT); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 24); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 24); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 24); + multicast(self.origin,MULTICAST_PHS_R); + + remove(self); +} + +void flamestreamThink() +{ + makevectors(self.angles); + + float old_health; + vector other_org; + + traceline(self.origin, self.origin + '0 0 -256', FALSE, self); + + if (trace_ent) + { + if (isFlammable()) + { + spawn_burner(trace_ent,FALSE); + } + + other_org=trace_ent.origin; + old_health=trace_ent.health; + if(trace_ent.health<=0&&old_health>0) + { + smolder(other_org); + } + } + + self.angles = vectoangles(self.movedir); + + traceline(self.origin, self.origin + self.movedir * 450, FALSE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_FIREWALL); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 8.0); + multicast(self.origin,MULTICAST_PVS); + + if (self.lifetime < time) self.touch(); + + self.think = flamestreamThink; + thinktime self : 0.3; +} + +// regular attack +void flamestream_fire () +{ + + self.effects (+) EF_MUZZLEFLASH; + self.greenmana-=4; + + self.punchangle_x = -2; + makevectors(self.v_angle); + self.velocity+=normalize(v_forward) * -100; + self.flags(-)FL_ONGROUND; + + newmis=spawn(); + newmis.classname="flamestream"; + newmis.owner=self; + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.solid=SOLID_BBOX; + newmis.touch=flamestream_touch; + newmis.dmg=40; + newmis.lifetime=time+2; + newmis.o_angle=self.origin+self.proj_ofs+v_forward*16-v_right*16-v_up*16; + newmis.movedir=v_forward; + + newmis.speed=1500+random(50); + newmis.velocity=newmis.movedir*newmis.speed; + setmodel(newmis,"models/null.spr"); + setsize(newmis,'-6 -6 -6','6 6 6'); + newmis.level=0; + newmis.hull=HULL_POINT; + setorigin(newmis,newmis.o_angle); + newmis.wallspot=newmis.origin; + newmis.count = 20; + newmis.cnt = 0; + newmis.effects (+) EF_NODRAW; + + newmis.think=flamestreamThink; + thinktime newmis : 0.3; + + newmis.angles = vectoangles(newmis.movedir); + + traceline(newmis.origin, newmis.origin + newmis.movedir * 450, FALSE, newmis); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_FIREWALL); + WriteCoord (MSG_MULTICAST, newmis.origin_x); + WriteCoord (MSG_MULTICAST, newmis.origin_y); + WriteCoord (MSG_MULTICAST, newmis.origin_z); + WriteByte (MSG_MULTICAST, newmis.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, newmis.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 8.0); + multicast(self.origin,MULTICAST_PVS); +} + + + + + + + + + + + + + + + +void flameball_touch() +{ + if (other.takedamage) + { + float old_health; + vector other_org; + +// sound(self,CHAN_BODY,"succubus/flamend.wav",0.5,ATTN_NORM); + other_org=other.origin; + old_health=other.health; + T_Damage(other,self,self.owner,random(10,20)); + if(other.health<=0&&old_health>0) + smolder(other_org); + } +/* else//no need for this why damage it if it can't take damage? + { + T_Damage(other, self.owner, self.owner, 10); + }*/ + + // these'll be made on the client + +/* rand = random(); + + if (rand < 0.2) + starteffect(CE_SM_EXPLOSION, self.origin-self.movedir*6, '0 0 6', 0); + else if (rand < 0.3) + starteffect(CE_FBOOM, self.origin-self.movedir*6, '0 0 6', 0); + else + starteffect(CE_BOMB, self.origin-self.movedir*6, '0 0 6', 0);*/ + + remove(self); +} + +void flameball_think() +{ +// starteffect(CE_FLAMESTREAM, self.origin, '0 0 2', 0); + + self.think = SUB_Remove; + thinktime self : 2; +} + +void flameball_spawn(vector pos, entity targ) +{ + newmis = spawn(); + newmis.classname = "flameball"; + newmis.owner = self.owner; + + setmodel(newmis, "models/sucwp1p.mdl"); + setsize(newmis, '-3 -3 -3', '3 3 3'); + newmis.hull = HULL_POINT; + newmis.solid = SOLID_BBOX; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.drawflags (+) MLS_ABSLIGHT; + newmis.abslight = 0.5; + newmis.frame = 4; + newmis.effects (+) EF_NODRAW; // these'll be made on the client + + setorigin(newmis, pos); + + pos = targ.origin - newmis.origin; + + pos = normalize(pos); + + pos *= 800 + random(100); + + newmis.velocity = pos; + newmis.angles = vectoangles(newmis.velocity); + newmis.movedir = normalize(newmis.velocity); + +// starteffect(CE_FLAMESTREAM, newmis.origin, '0 0 0', 0); + + newmis.touch = flameball_touch; + newmis.think = flameball_think; + + thinktime newmis : 0.05; +} + +void flameswarmBoom() +{ + local vector rand; + + if (self.lifetime < time || self.lockentity.origin == '0 0 0') + { + self.lockentity.effects (-) EF_POWERFLAMEBURN; + remove(self); + return; + } + + if (self.attack_finished < time) + { + sound(self,CHAN_BODY,"succubus/flamend.wav",0.5,ATTN_NORM); + self.attack_finished = time + 1.5; + } + + makevectors(self.lockentity.angles); + + rand = self.lockentity.origin + '0 0 200' + randomv('-140 -140 -140', '140 140 140'); + + traceline(self.lockentity.origin, rand, TRUE, self); + + flameball_spawn(trace_endpos, self.lockentity); + + self.think = flameswarmBoom; + thinktime self : 0.1; +} + +void flameswarm_touch () +{ + entity found,loser; + float lastdist,dist; + float old_health; + vector loser_org; + + self.velocity = '0 0 0'; + + if(other.classname=="flamestream") + return; + + loser=other; + if(!loser.takedamage) + { + found=findradius(self.origin,200); + lastdist=200; + dist=0; + while(found) + { + dist=vlen((loser.absmin+loser.absmax)*0.5-self.origin); + if(dist0) + smolder(loser_org); + + sound(self,CHAN_BODY,"succubus/flampow.wav",0.5,ATTN_NORM); + + self.lockentity = loser; + self.lifetime = time + 3; + + self.solid = SOLID_NOT; + self.effects (+) EF_NODRAW; + loser.effects (+) EF_POWERFLAMEBURN; + self.think = flameswarmBoom; + thinktime self : 0.1; + return; + } +} + + + + + + +void flameswarmThink() +{ + self.angles = vectoangles(self.movedir); + makevectors(self.angles); + + traceline(self.origin, self.origin + self.movedir * 450, FALSE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_POWERFLAME); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 8.0); + WriteLong (MSG_MULTICAST, time); + multicast(self.origin,MULTICAST_PVS); + + if (self.lifetime < time) self.touch(); + + self.think = flameswarmThink; + thinktime self : 0.3; +} + +// tome of power attack +void flameswarm_fire() +{ + makevectors(self.v_angle); + self.greenmana-=8; + self.effects(+)EF_MUZZLEFLASH; + + self.velocity+=normalize(v_forward) * -200; + self.punchangle_x = -6; + + self.flags(-)FL_ONGROUND; + + newmis=spawn(); + newmis.classname="flamestream"; + newmis.owner=self; + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.solid=SOLID_BBOX; + newmis.abslight=1; + newmis.touch=flameswarm_touch; + newmis.dmg=40; + newmis.lifetime=time+2; + + newmis.o_angle=self.origin+self.proj_ofs+v_forward*16-v_right*24-v_up*16; + newmis.movedir=v_forward; + + newmis.speed=1250+random(50); + newmis.velocity=newmis.movedir*newmis.speed; + setmodel(newmis,"models/null.spr"); + setsize(newmis,'-6 -6 -6','6 6 6'); + newmis.level=0; + newmis.hull=HULL_POINT; + setorigin(newmis,newmis.o_angle); + newmis.wallspot=newmis.origin; + newmis.angles = vectoangles(newmis.velocity); + newmis.effects (+) EF_NODRAW; + + newmis.think=flameswarmThink; + thinktime newmis : 0.3; + + newmis.angles = vectoangles(newmis.movedir); + + + + traceline(newmis.origin, newmis.origin + newmis.movedir * vlen(newmis.velocity)*.3, FALSE, newmis); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_POWERFLAME); + WriteCoord (MSG_MULTICAST, newmis.origin_x); + WriteCoord (MSG_MULTICAST, newmis.origin_y); + WriteCoord (MSG_MULTICAST, newmis.origin_z); + WriteByte (MSG_MULTICAST, newmis.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, newmis.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 8.0); + WriteLong (MSG_MULTICAST, time); + multicast(self.origin,MULTICAST_PVS); +} + +/*====================== +ACTION +select +deselect +ready loop +relax loop +fire once +fire loop +ready to relax(after short delay) +relax to ready(Fire delay? or automatic if see someone?) +=======================*/ + + +void()flameorb_ready_power; +void()flameorb_ready_normal; +void flameorb_fire (void) +{ + + if(self.artifact_active&ART_TOMEOFPOWER) + self.wfs = advanceweaponframe($powern135,$powern148); + else + self.wfs = advanceweaponframe($normal51,$normal64); + /*if(self.button0&&self.weaponframe>$normal60 &&!self.artifact_active&ART_TOMEOFPOWER) + self.weaponframe=$normal60;*/ + + self.th_weapon=flameorb_fire; + self.last_attack=time; + if(self.wfs==WF_CYCLE_WRAPPED||self.greenmana<1||(self.greenmana<10&&self.artifact_active&ART_TOMEOFPOWER)) + { + self.t_width=-1; + self.weaponframe_cnt=0; + if(!self.artifact_active&ART_TOMEOFPOWER) + { + self.aflag=FALSE; + //self.attack_finished=time+0.2; + self.attack_finished=time+0.5; // 0.2 is REALLY fast for an attack this visually expensive + flameorb_ready_normal(); + } + else + { + self.attack_finished = time + 1; + flameorb_ready_power(); + } + } + else if(self.weaponframe==$normal52) + { + if(self.t_width==-1) + { + sound(self,CHAN_BODY,"succubus/flamstrt.wav",0.5,ATTN_NORM); + self.t_width=FALSE; + } + + if(self.t_width110) + self.wait=0; + else self.wait = self.wait - 1; + + if (self.trigger_field.classname == "player" && self.owner.classname != "player") + self.owner = self.trigger_field; + + if (self.trigger_field.waterlevel > 2) + if(self.trigger_field.watertype == CONTENT_LAVA) + { + if(self.trigger_field.classname=="player") + { + sprintname(self.owner,PRINT_MEDIUM,self.trigger_field); + sprint(self.owner," jumped out of the frying pan into the fire!\n"); + } + self.trigger_field.effects = 0; + self.trigger_field.onfire = 0; + remove(self); +// FireDie(); + } + else + { + if(self.trigger_field.classname=="player") + { + sound (self.owner, CHAN_WEAPON, "misc/fout.wav", 1, ATTN_NORM); + sprintname(self.owner,PRINT_MEDIUM,self.trigger_field); + } + sprint(self.owner," saved his ass by jumping in the water!\n"); + self.trigger_field.effects = 0; + self.trigger_field.onfire = 0; + remove(self); + } + + if ((self.waterlevel > 2) || (self.watertype == CONTENT_WATER) || (self.watertype == CONTENT_SLIME) || (pointcontents(self.origin) == CONTENT_WATER) || (pointcontents(self.origin) == CONTENT_SLIME)) + { + sound (self.owner, CHAN_WEAPON, "misc/fout.wav", 1, ATTN_NORM); + sprint(self.owner,"Fireball fizzled underwater\n"); + self.trigger_field.effects = 0; + self.trigger_field.onfire = 0; + remove(self); + } + +// if (self.aflag != 5) +// { + //Non-explosive death + if ((self.wait < 1) || (self.trigger_field.health<=0)) + { + self.trigger_field.effects = 0; + self.trigger_field.onfire = 0; + remove(self); + } +// } +// else if (self.wait < 1 || self.trigger_field.health <= 6) +// { + //explosive fireball death +// self.dmg = 2; +// self.trigger_field.onfire = 0; +// self.trigger_field.effects = 0; +// FireDie(); +// } + if(self.trigger_field.onfire>0.5) + self.trigger_field.onfire=0.5;//Max out damage at 0.5 per think + if (!self.trigger_field.flags&FL_FIRERESIST) + { + if(self.aflag>0.1) + damagemult=self.aflag; + else + damagemult=0.1; + if(self.trigger_field.flags&FL_FIREHEAL) + self.trigger_field.health=self.trigger_field.health+2*damagemult*self.trigger_field.onfire; + else + T_Damage (self.trigger_field, self, self.owner, damagemult*self.trigger_field.onfire); + } + + if(self.trigger_field.health<=17) + if(self.trigger_field.thingtype==THINGTYPE_WOOD) + { + self.trigger_field.skin=111; + self.trigger_field.deathtype="burnt crumble"; + } + else if(self.trigger_field.thingtype==THINGTYPE_FLESH) + { + self.trigger_field.skin=112; + self.trigger_field.deathtype="burnt crumble"; + } + + //FIXME: need 3 different fire models to put on them, + //randomly choose one & scale it to their size, add more + // if they're more on fire. No more than 3. Only one + //fire sound, from "invisible" one doing actual damage. + //Use movechain function to link flames to target + if(random()<0.5) + SpawnFlameAt (self.origin);//This is causing an edict overflow hard crash... + + self.origin = self.trigger_field.origin + '0 0 6'; + self.think = FireDamage; + thinktime self : 0.1; +}; + +void() FireTouch2 = +{ + self.trigger_field.effects = EF_BRIGHTLIGHT; + if(self.trigger_field.onfire<=0) + self.trigger_field.onfire = 1; + self.think=FireDamage; + thinktime self : 0; +}; + +void() FireTouch = +{ + local float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + if (other.takedamage&&other.thingtype!=1&&other.thingtype!=0&&other.thingtype!=3&&other.skin<111) + { + if(other.onfire) + { + other.onfire=other.onfire+0.1; + remove(self); + } + else + other.onfire=0.1; + sound (self, CHAN_WEAPON, "misc/combust.wav", 1, ATTN_NORM); + self.trigger_field = other; + self.origin = other.origin + '0 0 6'; + + if (other.classname == "player" || self.aflag == 5) + self.wait = 180; + else + self.wait = 40; + + setsize (self, '0 0 0', '0 0 0'); + + self.think=FireTouch2; + thinktime self : 0; + self.movetype = MOVETYPE_NOCLIP; + self.velocity = '0 0 0' ; + self.avelocity = '0 0 1000'; + if ((other.waterlevel < 2) && (other.classname == "player")) + sprint(other, "You're burning up!\n"); + return; + } + else if (self.movetype == MOVETYPE_FLYMISSILE) + remove(self); +// FireDie(); + sound (self, CHAN_WEAPON, "misc/fburn_sm.wav", 0.75, ATTN_STATIC); // bounce sound + SpawnPuff(self.origin,'0 0 0', 10,other); +// spawn_touchblood (10); + SpawnFlameAt (self.origin); + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; + if (self.aflag == 5) + { + self.trigger_field=self.enemy; + thinktime self : 0.05; + self.think = FireTouch2; + } +}; + +void () FireThink = +{ + + if (pointcontents(self.origin)==CONTENT_WATER||pointcontents(self.origin)==CONTENT_SLIME||(self.waterlevel > 2)) + FireFizzle(); + self.attack_finished = self.attack_finished + 0.1; + if (self.attack_finished > 5) +// if(self.model=="models/lavaball.spr") +// FireDie(); +// else + remove(self); + thinktime self : 0.1; + self.think = FireThink; +}; + +void(entity loser) SpawnFlameOn = +{ +if(pointcontents(loser.origin)<-2) + return; +//Used by player, archvile, and stickmine +local entity fire; + if (pointcontents(self.origin) < -2) + { + sound (self, CHAN_WEAPON, "misc/fout.wav", 1, ATTN_NORM); + return; + } + fire = spawn (); + fire.controller = self; + fire.movetype = MOVETYPE_NOCLIP; + fire.solid = SOLID_NOT; + fire.velocity = '0 0 0' ; + fire.avelocity = '0 0 1000'; + fire.classname = "fire"; + fire.dmg = 1; + fire.aflag = 0.25; + setmodel (fire, "models/null.spr"); + fire.effects=EF_NODRAW; + setsize (fire, '0 0 0', '0 0 0'); + if(self.classname=="fireballblast"||self.classname=="flaming arrow") + { + fire.enemy = loser; + setorigin (fire, (loser.absmax+loser.absmin)*0.5); + fire.owner=self; + } + else + { + setorigin (fire, (self.enemy.absmax+self.enemy.absmin)*0.5); + fire.enemy = self.enemy; + fire.owner = self.controller; + } + sound (fire, CHAN_WEAPON, "misc/combust.wav", 1, ATTN_NORM); + if(!loser.onfire) + loser.onfire=0.1; + else + { + loser.onfire+=0.1; + remove(fire); + return; + } + fire.trigger_field = loser; + + if (loser.classname == "player") + fire.wait = 120; + else + fire.wait = 40; + thinktime fire : 0.1; + fire.think=FireTouch2; +}; + +void(vector org) SpawnFlameAt = +{ +if(pointcontents(self.origin)<-2) + return; +local entity fireflame; +local float xorg, yorg, zorg; + fireflame = spawn(); + setmodel (fireflame, "models/flame2.mdl"); + fireflame.movetype = MOVETYPE_FLY; + fireflame.solid = SOLID_NOT; + fireflame.classname = "missile"; + fireflame.drawflags(+)MLS_ABSLIGHT; + fireflame.abslight=0.5; + fireflame.frame = rint(random()); + setsize (fireflame, '-2 -2 -2', '1 1 1'); + xorg = random(-15,15); + yorg = random(-15,15); + zorg = random(-25,25); + setorigin (fireflame, org + v_forward * xorg + v_right * yorg + v_up * zorg); + fireflame.velocity_x += random(-40,40); + fireflame.velocity_y += random(-40,40); + fireflame.velocity_z += random(300); + fireflame.avelocity = '0 0 0'; + if (random() < 0.3) + sound (self, CHAN_WEAPON, "misc/fburn_sm.wav", 1, ATTN_NORM); + thinktime fireflame : 0.5; // remove after half second + fireflame.think = SUB_Remove; +}; + +/* +================ +FlameTouch +================ +*/ +void () FlameTouch = +{ + local float rn; +//Scale size relative to other.size? + if (other.takedamage) + { + if(other.flags&FL_FIREHEAL) + other.health=other.health+1; + else if (!other.flags&FL_FIRERESIST) + T_Damage(other,self,self.owner,5); + if(other.thingtype==THINGTYPE_FLESH||other.thingtype==THINGTYPE_WOOD) + { + //set on fire + rn = random(); + // 50% chance + if (rn <= 0.5||other.onfire>=1) + { + if(other.onfire) + other.onfire = other.onfire + 0.1; + remove(self); + } + other.onfire = other.onfire + 0.1; + if(self.owner.movetype==MOVETYPE_NONE) + self.wait = 20; + else self.wait = 60; + self.aflag = 0.1; + self.trigger_field = other; + self.think = FireTouch2; + thinktime self : 0; + self.solid = SOLID_NOT; + setmodel (self,"models/flame2.mdl"); + } + else if(self.netname=="firespike") + { + //FIXME:else sprite + remove(self); + } + } + else + { + if(self.netname=="firespike") + { + if(other.thingtype==THINGTYPE_FLESH||other.thingtype==THINGTYPE_WOOD) + SpawnFlameAt(self.origin); + //FIXME:else sprite + remove(self); + } + else + { + self.velocity = '0 0 0'; + self.velocity_z = random(24,48); + } + } +}; + + + + +/* +================ +W_FireFlame +================ +*/ +void(float offset) W_FireFlame = +{ + local entity flame; + local float rn; + + if(self.movetype!=MOVETYPE_NONE) + { + if (self.waterlevel > 2) + { +// makevectors (self.v_angle); + + rn = random(); + if (rn < 0.5) + sound (self, CHAN_WEAPON, "player/swim1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_WEAPON, "player/swim2.wav", 1, ATTN_NORM); + flame=spawn(); + flame.owner=flame; + setorigin(flame,self.origin+self.proj_ofs + v_forward * 32 + v_up * random(8,16)); + flame.think=DeathBubblesSpawn; + thinktime flame : 0; + return; + } + + // Take away a shell +// self.currentammo = self.ammo_shells = self.ammo_shells - 1; + } + else if((random()>=0.1&&random()>=0.2)||(!other.takedamage)) + return; + sound (self, CHAN_WEAPON, "paladin/purfire.wav", 1, ATTN_NORM); + + flame = spawn (); + flame.owner = self; + flame.movetype = MOVETYPE_FLYMISSILE; + flame.solid = SOLID_BBOX; + flame.classname = "fire"; + flame.drawflags(+)MLS_ABSLIGHT; + flame.abslight=0.5; +// set flame speed + + if(self.classname=="player"&&self.playerclass==CLASS_PALADIN&&self.weapon==IT_WEAPON4) + { + self.punchangle_x= -1; + setmodel (flame, "models/purfir1.mdl"); + flame.netname="firespike"; + } + else + setmodel (flame, "models/flame2.mdl"); + setsize (flame, '0 0 0', '0 0 0'); + + if(self.movetype==MOVETYPE_NONE) + { + flame.velocity='0 0 100'; + setorigin (flame, self.origin + '0 0 16'); + } + else + { + makevectors (self.v_angle); + flame.velocity = normalize(v_forward)*700 + v_up*random(32) + v_right * random(0-offset,offset); + setorigin (flame, self.origin+self.proj_ofs + v_forward * 32 + v_up * random(-8,8)); + } + if(flame.netname=="firespike") + flame.angles=vectoangles(flame.velocity); + +// flame.effects = 6; + flame.touch = FlameTouch; + + flame.think = FireThink; + thinktime flame : 0; + self.attack_finished=time + 0.1; +}; diff --git a/flamswrd.hc b/flamswrd.hc new file mode 100644 index 0000000..331f547 --- /dev/null +++ b/flamswrd.hc @@ -0,0 +1,52 @@ +/* + * $Header: /HexenWorld/Siege/flamswrd.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +FLAME SWORD + +============================================================================== +*/ + +// For building the model +$cd q:\art\models\weapons\flamswrd\final +$origin 0 0 54 +$base base +$skin skin + +//============================================================================ + +$frame swg000 swg001 swg002 swg003 swg004 +$frame swg005 swg006 swg007 swg008 swg009 +$frame swg010 swg011 swg012 swg013 swg014 +$frame swg015 swg016 + + +//frame bswg000 bswg001 bswg002 bswg003 bswg004 +//$frame bswg005 bswg006 bswg007 bswg008 bswg009 +//$frame bswg010 bswg011 bswg012 bswg013 bswg014 +//$frame bswg015 + + +//============================================================================ + +// Flame Sword +void() player_swing1 = [$swg000, player_swing2 ] {self.weaponframe=1;}; +void() player_swing2 = [$swg001, player_swing3 ] {self.weaponframe=2;}; +void() player_swing3 = [$swg002, player_swing4 ] {self.weaponframe=3;}; +void() player_swing4 = [$swg003, player_swing5 ] {self.weaponframe=4;}; +void() player_swing5 = [$swg004, player_swing6 ] {self.weaponframe=5;}; +void() player_swing6 = [$swg005, player_swing7 ] {self.weaponframe=6;}; +void() player_swing7 = [$swg006, player_swing8 ] {self.weaponframe=7;}; +void() player_swing8 = [$swg007, player_swing9 ] {self.weaponframe=8;}; +void() player_swing9 = [$swg008, player_swing10 ] {self.weaponframe=9;}; +void() player_swing10 = [$swg009, player_swing11 ] {self.weaponframe=10;}; +void() player_swing11 = [$swg010, player_swing12 ] {self.weaponframe=11;}; +void() player_swing12 = [$swg011, player_swing13 ] {self.weaponframe=12;}; +void() player_swing13 = [$swg012, player_swing14 ] {self.weaponframe=13;}; +void() player_swing14 = [$swg013, player_swing15 ] {self.weaponframe=14;}; +void() player_swing15 = [$swg014, player_swing16 ] {self.weaponframe=15;}; +void() player_swing16 = [$swg015, player_swing1 ] {self.weaponframe=16;}; + diff --git a/fx.hc b/fx.hc new file mode 100644 index 0000000..145af23 --- /dev/null +++ b/fx.hc @@ -0,0 +1,483 @@ +/* + * $Header: /HexenWorld/Siege/fx.hc 7 5/25/98 1:38p Mgummelt $ + */ + +float WHITE_PUFF = 0; +float RED_PUFF = 1; +float GREEN_PUFF = 2; +float GREY_PUFF = 3; + + +void CreateTeleporterBodyEffect (vector org,vector vel,float framelength) +{ + starteffect(CE_TELEPORTERBODY, org,vel,framelength); +} + + +void CreateTeleporterSmokeEffect (vector org,vector vel,float framelength) +{ + starteffect(CE_TELEPORTERPUFFS, org,vel,framelength); +} + +// ============= SMOKE ================================ + +void CreateWhiteSmoke (vector org,vector vel,float framelength) +{ + starteffect(CE_WHITE_SMOKE, org,vel,framelength); +} + +void CreateRedSmoke (vector org,vector vel,float framelength) +{ + starteffect(CE_RED_SMOKE, org,vel, framelength); +} + +void CreateGreySmoke (vector org,vector vel,float framelength) +{ + starteffect(CE_GREY_SMOKE, org,vel, framelength); +} + +void CreateGreenSmoke (vector org,vector vel,float framelength) +{ + starteffect(CE_GREEN_SMOKE, org,vel, framelength); +} + +void CreateRedCloud (vector org,vector vel,float framelength) +{ + starteffect(CE_REDCLOUD, org,vel, framelength); +} + +// ============= FLASHES ================================ + +void CreateLittleWhiteFlash (vector spot) +{ + starteffect(CE_SM_WHITE_FLASH,spot); +} + +void CreateLittleBlueFlash (vector spot) +{ + starteffect(CE_SM_BLUE_FLASH,spot); +} + +void CreateBlueFlash (vector spot) +{ + starteffect(CE_BLUE_FLASH,spot); +} + +void CreateWhiteFlash (vector spot) +{ + starteffect(CE_WHITE_FLASH, spot); +} + +void CreateYRFlash (vector spot) +{ + starteffect(CE_YELLOWRED_FLASH,spot); +} + +// ============= EXPLOSIONS ============================= + +void CreateBlueExplosion (vector spot) +{ + starteffect(CE_BLUE_EXPLOSION,spot); +} + +void CreateExplosion29 (vector spot) +{ + starteffect(CE_BG_CIRCLE_EXP,spot); +} + +void CreateFireCircle (vector spot) +{ + starteffect(CE_SM_CIRCLE_EXP,spot); +} + +// ============= SPARKS ============================= + +void CreateRedSpark (vector spot) +{ + starteffect(CE_REDSPARK,spot); +} + +void CreateGreenSpark (vector spot) +{ + starteffect(CE_GREENSPARK,spot); +} + +void CreateBSpark (vector spot) +{ + starteffect(CE_BLUESPARK,spot); +} + +void CreateSpark (vector spot) +{ + starteffect(CE_YELLOWSPARK,spot); +} + +//FIXME:This should be a temp entity +void splash_run (void) +{ + float result; + + result = AdvanceFrame(0,5); + + self.nextthink = time + HX_FRAME_TIME; + self.think = splash_run; + + if (result == AF_END) + { + self.nextthink = time + HX_FRAME_TIME; + self.think = SUB_Remove; + } +} + +void CreateWaterSplash (vector spot) +{ + entity newent; + + newent = spawn(); + setmodel (newent, "models/wsplash.spr"); + + setorigin (newent, spot); + newent.movetype = MOVETYPE_NOCLIP; + newent.solid = SOLID_NOT; + newent.velocity = '0 0 0'; + newent.nextthink = time + 0.05; + newent.think = splash_run; + +} + + +/* +================ +SpawnPuff +================ +*/ +void SpawnPuff (vector org, vector vel, float damage,entity victim) +{ + float part_color; + float rad; + + if (victim.thingtype==THINGTYPE_FLESH && victim.classname!="mummy" && victim.netname != "spider") + part_color = 256 + 8 * 16 + random(9); //Blood red + else if ((victim.thingtype==THINGTYPE_GREYSTONE) || (victim.thingtype==THINGTYPE_BROWNSTONE)) + part_color = 256 + 20 + random(8); // Gray + else if (victim.thingtype==THINGTYPE_METAL) + part_color = 256 + (8 * 15); // Sparks + else if (victim.thingtype==THINGTYPE_WOOD||victim.thingtype==THINGTYPE_DIRT) + part_color = 256 + (5 * 16) + random(8); // Wood chunks + else if (victim.thingtype==THINGTYPE_ICE) + part_color = 406+random(8); // Ice particles + else if (victim.netname == "spider") + part_color = 256 + 183 + random(8); // Spider's have green blood + else + part_color = 256 + (3 * 16) + 4; // Dust Brown + + rad=vlen(vel); + if(!rad) + rad=random(10,20); + particle4(org,rad,part_color,PARTICLETYPE_FASTGRAV,2 * damage); +} + +/*----------------------------------------- + redblast - the red flash sprite + -----------------------------------------*/ +void(vector spot) CreateRedFlash = +{ + starteffect(CE_RED_FLASH,spot); +}; + +void() DeathBubblesSpawn; + +void () flash_remove = +{ + remove(self); +}; + +void GenerateTeleportSound (entity center) +{ +string telesnd; +float r; + r=rint(random(4))+1; + if(r==1) + telesnd="misc/teleprt1.wav"; + else if(r==2) + telesnd="misc/teleprt2.wav"; + else if(r==3) + telesnd="misc/teleprt3.wav"; + else if(r==4) + telesnd="misc/teleprt4.wav"; + else + telesnd="misc/teleprt5.wav"; + sound(center,CHAN_AUTO,telesnd,1,ATTN_NORM); +} + +void GenerateTeleportEffect(vector spot1,float teleskin) +{ +// entity sound_ent; + + if (self.attack_finished > time) + return; + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_HWTELEPORT); + WriteCoord (MSG_MULTICAST, spot1_x); + WriteCoord (MSG_MULTICAST, spot1_y); + WriteCoord (MSG_MULTICAST, spot1_z); + WriteShort (MSG_MULTICAST, teleskin); + multicast(spot1,MULTICAST_PHS_R); + +/* + sound_ent = spawn(); + setorigin(sound_ent,spot1); + GenerateTeleportSound(sound_ent); + sound_ent.think = SUB_Remove; + thinktime sound_ent : 2; + + CreateTeleporterBodyEffect (spot1,'0 0 0',teleskin); // 3rd parameter is the skin + + CreateTeleporterSmokeEffect (spot1,'0 0 0',HX_FRAME_TIME); + CreateTeleporterSmokeEffect (spot1 + '0 0 64','0 0 0',HX_FRAME_TIME); + +// GenerateTeleportSound(newent); +// if (self.scale < 0.11) +// { +// particle4(self.origin + '0 0 40',random(5,10),20,PARTICLETYPE_FASTGRAV,random(20,30)); +// particle4(self.origin + '0 0 40',random(5,10),250,PARTICLETYPE_FASTGRAV,random(20,30)); +// remove(self); +// } +*/ +} + +void smoke_generator_use(void) +{ + self.use = smoke_generator_use; + self.nextthink = time + HX_FRAME_TIME; + if (!self.wait) + self.wait = 2; + self.owner = other; + + if (self.lifespan) + self.lifetime = time + self.lifespan; + +} + +void smoke_generator_run(void) +{ + if (self.thingtype == WHITE_PUFF) + CreateWhiteSmoke(self.origin, '0 0 8', HX_FRAME_TIME *3); + else if (self.thingtype == RED_PUFF) + CreateRedSmoke(self.origin, '0 0 8', HX_FRAME_TIME *3); + else if (self.thingtype == GREEN_PUFF) + CreateRedSmoke(self.origin, '0 0 8', HX_FRAME_TIME *3); + else if (self.thingtype == GREY_PUFF) + CreateGreySmoke(self.origin, '0 0 8', HX_FRAME_TIME *3); + + self.nextthink = time + random(self.wait); + self.think = smoke_generator_run; + + if ((self.lifespan) && (self.lifetime < time)) + remove(self); +} + +/*QUAKED fx_smoke_generator (0 1 1) (-8 -8 -8) (8 8 8) +Generates smoke puffs +-------------------------FIELDS------------------------- +wait - how often it should generate smoke (default 2) +thingtype - type of smoke to generate + 0 - white puff (fire place) + 1 - red (lava) + 2 - green (slime) + 3 - grey (oil) + +lifespan - fill this in and it will only puff for this long +-------------------------------------------------------- +*/ +void() fx_smoke_generator = +{ + + setmodel(self, "models/null.spr"); + + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_NONE; + + setsize (self,'0 0 0' , '0 0 0'); + + self.th_die = SUB_Remove; + + if (!self.targetname) // Not targeted by anything so puff away + self.nextthink = time + HX_FRAME_TIME; + + self.use = smoke_generator_use; + + if (!self.wait) + self.wait = 2; + + + self.think = smoke_generator_run; +}; + + +void (vector org) fx_flash = +{ + local entity newent; + + newent = spawn(); + setmodel (newent, "models/s_bubble.spr"); + +// setmodel (newent, newent.model); +// newent.modelindex = 0; +// newent.model = ""; + + + setorigin (newent, org + '0 0 24'); + newent.movetype = MOVETYPE_NOCLIP; + newent.solid = SOLID_NOT; + newent.velocity = '0 0 0'; + newent.nextthink = time + 0.5; + newent.think = flash_remove; + newent.classname = "bubble"; + + newent.effects = EF_BRIGHTLIGHT; + + setsize (newent, '-8 -8 -8', '8 8 8'); + +}; +/* +void () friction_change_touch = +{ + if (other == self.owner) + return; + + if (other.classname == "player") + other.friction=self.friction; + +}; +*/ +/*QUAK-ED fx_friction_change (0 1 1) ? + +Set the friction within this area. + +-------------------------FIELDS------------------------- +'friction' : this is how quickly the player will slow down after he ceases indicating movement (lets go of arrow keys). + + 1 : normal friction + >0 & <1 : slippery + >1 : high friction +-------------------------------------------------------- +*/ +/* +void() fx_friction_change = +{ + self.movetype = MOVETYPE_NONE; + self.owner = self; + self.solid = SOLID_TRIGGER; + setorigin (self, self.origin); + setmodel (self, self.model); + self.modelindex = 0; + self.model = ""; + + setsize (self, self.mins , self.maxs); + + self.touch = friction_change_touch; +}; +*/ + +void() explosion_done = +{ + self.effects=EF_DIMLIGHT; +}; + +void() explosion_use = +{ +/* + if (self.spawnflags & FLASH) + { + self.effects=EF_BRIGHTLIGHT; + self.think=p_explosion_done; + self.nextthink= time + 1; + } +*/ + sound (self, CHAN_BODY, self.noise1, 1, ATTN_NORM); + + particleexplosion(self.origin,self.color,self.exploderadius,self.counter); + +}; + +/*QUAK-ED fx_particle_explosion (0 1 1) ( -5 -5 -5) (5 5 5) FLASH + Gives off a spray of particles like an explosion. +-------------------------FIELDS------------------------- + FLASH will cause a brief flash of light. + + "color" is the color of the explosion. Particle colors dim as they move away from the center point. + + color values : + 31 - white + 47 - light blue + 63 - purple + 79 - light green + 85 - light brown + 101 - red (default) + 117 - light blue + 133 - yellow + 149 - green + 238 - red to orange + 242 - purple to red + 246 - green to purple + 250 - blue - green + 254 - yellow to blue + + "exploderadius" is the distance the particles travel before disappearing. 1 - 10 (default 5) + + "soundtype" the type of sound made during explosion + 0 - no sound + 1 - rocket explosion (default) + 2 - grenade shoot + + "counter" the number of particles to create + 1 - 1024 + 512 (default) + +-------------------------------------------------------- +*/ +/* +void() fx_particle_explosion = +{ + self.effects=0; + self.use=explosion_use; + + self.movetype = MOVETYPE_NOCLIP; + self.owner = self; + self.solid = SOLID_NOT; + setorigin (self, self.origin); + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + + // Explosion color + if ((!self.color) || (self.color>254)) + self.color=101; + + // Explosion sound is what type???? + if (self.soundtype>2) + self.soundtype=0; + else if (!self.soundtype) + self.soundtype=1; + + if (self.soundtype==0) + self.noise1 = ("misc/null.wav"); + else if (self.soundtype==1) + self.noise1 = ("weapons/explode.wav"); + else if (self.soundtype==2) + self.noise1 = ("weapons/grenade.wav"); + + self.exploderadius = 10 - self.exploderadius; // This is backwards in builtin function + + // Explosion radius + if ((self.exploderadius<1) || (self.exploderadius>10)) + self.exploderadius=5; + + // Particle count + if ((self.counter<1) || (self.counter>1024)) + self.counter=512; + +}; +*/ + diff --git a/gauntlet.hc b/gauntlet.hc new file mode 100644 index 0000000..f35a7fe --- /dev/null +++ b/gauntlet.hc @@ -0,0 +1,263 @@ +/* +============================================================================== + +GAUNTLET + +============================================================================== +*/ + +// For building the model +$cd q:/art/models/weapons/gauntlet/final +$origin 0 5 10 +$base base4 512 473 +$skin skin3 + +// FRAME: 1 +$frame GntRoot1 + +// FRAMES: 2 - 14 +$frame 1stGnt1 1stGnt2 1stGnt3 1stGnt4 1stGnt5 +$frame 1stGnt6 1stGnt7 1stGnt8 1stGnt9 1stGnt10 +$frame 1stGnt11 1stGnt12 1stGnt14 + +// FRAMES 15 - 28 +$frame 2ndGnt1 2ndGnt2 2ndGnt3 2ndGnt4 2ndGnt5 +$frame 2ndGnt6 2ndGnt7 2ndGnt8 2ndGnt9 2ndGnt10 +$frame 2ndGnt11 2ndGnt12 2ndGnt13 2ndGnt15 +$frame 2ndGnt16 2ndGnt19 + +// FRAMES 29 - 40 +$frame 3rdGnt1 3rdGnt3 3rdGnt5 +$frame 3rdGnt10 +$frame 3rdGnt11 3rdGnt12 3rdGnt13 3rdGnt14 3rdGnt15 +$frame 3rdGnt17 +$frame 3rdGnt21 3rdGnt22 + +// Frames 41 - 54 +$frame GntTap1 GntTap2 GntTap3 GntTap4 GntTap5 +$frame GntTap11 GntTap12 GntTap13 GntTap14 GntTap15 +$frame GntTap16 GntTap17 GntTap18 GntTap19 + + +// FRAMES: 55 - 67 +$frame 7thGnt1 7thGnt2 7thGnt3 +$frame 7thGnt6 7thGnt7 7thGnt8 7thGnt9 7thGnt10 +$frame 7thGnt11 7thGnt12 7thGnt13 7thGnt14 +$frame 7thGnt19 + + +float GAUNT_BASE_DAMAGE = 16; +float GAUNT_ADD_DAMAGE = 12; +float GAUNT_PWR_BASE_DAMAGE = 30; +float GAUNT_PWR_ADD_DAMAGE = 20; +float GAUNT_PUSH = 4; + +void W_SetCurrentWeapon(void); + + +void gauntlet_fire (float anim) +{ + vector source; + vector org; + float damg; + entity hitGuy; + + makevectors (self.v_angle); + source = self.origin + self.proj_ofs; + traceline (source, source + v_forward*64, FALSE, self); // Straight in front + + if (trace_fraction == 1.0) + { + traceline (source, source + v_forward*64 - (v_up * 30), FALSE, self); // 30 down + + if (trace_fraction == 1.0) + { + traceline (source, source + v_forward*64 + v_up * 30, FALSE, self); // 30 up + + if (trace_fraction == 1.0) + return; + } + } + + org = trace_endpos + (v_forward * 4); + + if (trace_ent.takedamage) + { + SpawnPuff (org, '0 0 0', 20,trace_ent); + + if (self.artifact_active & ART_TOMEOFPOWER) + { + //damg = GAUNT_PWR_BASE_DAMAGE + random(GAUNT_PWR_ADD_DAMAGE); + if(trace_ent.classname == "player") + { + damg = 30 + random(25); + } + else + { + damg = 2; // let the wall collision do the damage + } + org = trace_endpos + (v_forward * -1); + CreateWhiteFlash(org); + sound (self, CHAN_WEAPON, "weapons/gauntht1.wav", 1, ATTN_NORM); + } + else + { + damg = GAUNT_BASE_DAMAGE + random(GAUNT_ADD_DAMAGE); + sound (self, CHAN_WEAPON, "weapons/gauntht1.wav", 1, ATTN_NORM); + } + + hitGuy = trace_ent; + + T_Damage (trace_ent, self, self, damg); + + if(self.artifact_active & ART_TOMEOFPOWER) + { + hitGuy.velocity += normalize(hitGuy.origin - self.origin)*800; + hitGuy.velocity_z += 600; + hitGuy.flags(-)FL_ONGROUND; + } + + + } + else + { // hit wall + sound (self, CHAN_WEAPON, "weapons/gauntht2.wav", 1, ATTN_NORM); + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_GUNSHOT); + WriteByte (MSG_BROADCAST, 1); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + + org = trace_endpos + (v_forward * -1); + org += '0 0 10'; + CreateWhiteSmoke(org,'0 0 2',HX_FRAME_TIME); + } +} + +void gauntlet_ready (void) +{ + self.th_weapon=gauntlet_ready; + self.weaponframe = $GntRoot1; +} + +void gauntlet_twitch (void) +{ + self.wfs = advanceweaponframe($GntTap1,$GntTap19); + self.th_weapon = gauntlet_twitch; + + if (self.weaponframe == $GntTap3) + sound (self, CHAN_VOICE, "fx/wallbrk.wav", 1, ATTN_NORM); + + if (self.wfs == WF_LAST_FRAME) + gauntlet_ready(); +} + +void gauntlet_select (void) +{ + self.wfs = advanceweaponframe($2ndGnt6,$2ndGnt1); + self.weaponmodel = "models/gauntlet.mdl"; + self.th_weapon=gauntlet_select; + self.last_attack=time; + self.attack_cnt = 0; + + if (self.wfs == WF_LAST_FRAME) + { + self.attack_finished = time - 1; + gauntlet_twitch(); + } +} + +void gauntlet_deselect (void) +{ + self.wfs = advanceweaponframe($2ndGnt1,$2ndGnt6); + self.th_weapon=gauntlet_deselect; + self.oldweapon = IT_WEAPON1; + + if (self.wfs == WF_LAST_FRAME) + { + W_SetCurrentAmmo(); + } +} + +void gauntlet_d (void) +{ + self.wfs = advanceweaponframe($7thGnt3,$7thGnt19); + self.th_weapon = gauntlet_d; + + if (self.weaponframe == $7thGnt6) // Frame 57 + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $7thGnt9) // Frame 63 + gauntlet_fire(4); + + if (self.wfs == WF_LAST_FRAME) + gauntlet_ready(); +} + +void gauntlet_c (void) +{ + self.wfs = advanceweaponframe($3rdGnt1,$3rdGnt22); + self.th_weapon = gauntlet_c; + + if (self.weaponframe == $3rdGnt5) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $3rdGnt12) + gauntlet_fire(3); + + if (self.wfs == WF_LAST_FRAME) + gauntlet_ready(); +} + +void gauntlet_b (void) +{ + self.wfs = advanceweaponframe($2ndGnt1,$2ndGnt19); + self.th_weapon = gauntlet_b; + + if ((self.weaponframe == $2ndGnt4) || (self.weaponframe == $2ndGnt5)) + self.weaponframe == $2ndGnt6; + + if (self.weaponframe == $2ndGnt6) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $2ndGnt9) + gauntlet_fire(2); + + if (self.wfs == WF_LAST_FRAME) + gauntlet_ready(); +} + +void gauntlet_a (void) +{ + self.wfs = advanceweaponframe($1stGnt1,$1stGnt14); + self.th_weapon = gauntlet_a; + + if (self.weaponframe == $1stGnt2) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $1stGnt4) + gauntlet_fire(1); + + if (self.wfs == WF_LAST_FRAME) + gauntlet_ready(); +} + +void pal_gauntlet_fire(void) +{ + +// r = random(); // Eventually attacks will be random in order + + if (self.attack_cnt < 1) + gauntlet_a (); + else if (self.attack_cnt < 2) + gauntlet_b (); + else if (self.attack_cnt < 3) + gauntlet_c (); + else if (self.attack_cnt < 4) + { + gauntlet_d (); + self.attack_cnt=-1; + } + + self.attack_cnt += 1; + + self.attack_finished = time + 0.5; +} + diff --git a/gfire.hc b/gfire.hc new file mode 100644 index 0000000..b7a6cf9 --- /dev/null +++ b/gfire.hc @@ -0,0 +1,111 @@ +//FIRE HURT FIELD======================================================== +void fire_hurt_field_touch () +{ + if(self.attack_finished>time) + return; + if(self.inactive) + return; + if(other.health<=0) + return; + + self.attack_finished=time+HX_FRAME_TIME; + T_Damage(other,self,self,self.dmg); + if(self.owner.classname=="big greek fire") + if(!other.flags2&FL2_ONFIRE); + {//torch 'em + if(flammable(other)) + spawn_burner(other,TRUE); + } + else + other.fire_damage += 1;//burn more! + + if(self.t_width0.1) + { + self.scale-=0.1; + setsize(self.trigger_field,'-24 -24 0'*self.scale,'24 24 48'*self.scale); + thinktime self : 0.01; + self.dmg=self.trigger_field.dmg=self.scale*3; + } + else + { + remove(self.trigger_field); + stopSound(self,0); + remove(self); + } +} + +/*QUAKED light_newfire (0 1 0) (-10 -10 -13) (10 10 41) START_LOW HURT +Large yellow flame +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) +HURT = Will hurt things that touch it. +.dmg = how much to hurt people who touch fire - damage/20th of a second. Default = .2; + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +void spawn_big_fire(vector org) +{ +entity bigfire; + bigfire=spawn(); + + oself=self; + self = bigfire; + + self.dmg=2; + self.classname="big greek fire"; + self.drawflags(+)SCALE_ORIGIN_BOTTOM|DRF_TRANSLUCENT|MLS_FIREFLICKER; + self.scale = 1; + setmodel(self,"models/newfire.mdl"); + setorigin(self,org); + spawn_burnfield(org); + setsize(self.trigger_field,'-24 -24 0','24 24 48'); + sound (self,CHAN_LOOP+PHS_OVERRIDE_R, "misc/flamloop.wav", 0.5, ATTN_LOOP); + self.think = burn_out; + thinktime self : 10; + + self=oself; +}; + diff --git a/gib.hc b/gib.hc new file mode 100644 index 0000000..e77bafc --- /dev/null +++ b/gib.hc @@ -0,0 +1,159 @@ +/* + * $Header: /HexenWorld/Siege/gib.hc 5 5/25/98 1:38p Mgummelt $ + */ + +vector() ChunkVelocity = +{ + local vector v; + + v = randomv('-210 -210 -210', '210 210 280'); + + return v; +}; + +void(vector space) CreateSpriteChunks = +{ + local entity sprite; + + sprite = spawn(); + + space = randomv(space); + + setorigin (sprite, self.absmin + space); + if (self.thingtype==THINGTYPE_GLASS) + setmodel (sprite, "gfx/glass.spr"); + else + setmodel (sprite, "gfx/stone.spr"); + + setsize (sprite, '0 0 0', '0 0 0'); + sprite.movetype = MOVETYPE_BOUNCE; + sprite.solid = SOLID_NOT; + sprite.velocity = ChunkVelocity(); + sprite.think = SUB_Remove; + sprite.ltime = time; + sprite.nextthink = time + 1 + random()*1; + +}; + +void(vector space) CreateModelChunks = +{ + local entity chunk; + local float final; + + chunk = spawn(); + + space_x = space_x * random(); + space_y = space_y * random(); + space_z = space_z * random(); + + setorigin (chunk, self.absmin + space); + + if (self.thingtype==THINGTYPE_GLASS) + { + final = random(); + + if (final<0.20) + setmodel (chunk, "models/shard1.mdl"); + else if (final<0.40) + setmodel (chunk, "models/shard2.mdl"); + else if (final<0.60) + setmodel (chunk, "models/shard3.mdl"); + else if (final<0.80) + setmodel (chunk, "models/shard4.mdl"); + else + setmodel (chunk, "models/shard5.mdl"); + } + else if (self.thingtype==THINGTYPE_WOOD) + { + final = random(); + if (final < 0.25) + setmodel (chunk, "models/splnter1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/splnter2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/splnter3.mdl"); + else + setmodel (chunk, "models/splnter4.mdl"); + } + else if (self.thingtype==THINGTYPE_METAL) + { + final = random(); + if (final < 0.25) + setmodel (chunk, "models/metlchk1.mdl"); + else if (final < 0.50) + setmodel (chunk, "models/metlchk2.mdl"); + else if (final < 0.75) + setmodel (chunk, "models/metlchk3.mdl"); + else + setmodel (chunk, "models/metlchk4.mdl"); + } + else if (self.thingtype==THINGTYPE_FLESH) + { + final = random(); + if (final < 0.33) + setmodel (chunk, "models/flesh1.mdl"); + else if (final < 0.66) + setmodel (chunk, "models/flesh2.mdl"); + else + setmodel (chunk, "models/flesh3.mdl"); + } + else setmodel (chunk, "models/flesh1.mdl"); + + setsize (chunk, '0 0 0', '0 0 0'); + chunk.movetype = MOVETYPE_BOUNCE; + chunk.solid = SOLID_NOT; + chunk.velocity = ChunkVelocity(); + chunk.think = SUB_Remove; + chunk.avelocity_x = random()*1200; + chunk.avelocity_y = random()*1200; + chunk.avelocity_z = random()*1200; + chunk.ltime = time; + chunk.nextthink = time + 1 + random(); + +}; + +void () chunk_death = +{ + local vector space; + local float holdcount,spritecount,chunkcount; + + space = self.absmax - self.absmin; + + holdcount = space_x + space_y + space_z; + + spritecount = holdcount/8; + chunkcount = holdcount/16; + + if (self.thingtype==THINGTYPE_GLASS) + sound (self, CHAN_VOICE, "raven/glassbrk.wav", 1, ATTN_NORM); + else if (self.thingtype==THINGTYPE_WOOD) + sound (self, CHAN_VOICE, "raven/woodbrk.wav", 1, ATTN_NORM); + else if ((self.thingtype==THINGTYPE_GREYSTONE) || (self.thingtype==THINGTYPE_BROWNSTONE)||self.thingtype==THINGTYPE_DIRT) + sound (self, CHAN_VOICE, "raven/wallbrk.wav", 1, ATTN_NORM); + else if (self.thingtype==THINGTYPE_METAL) + sound (self, CHAN_VOICE, "raven/metalbrk.wav", 1, ATTN_NORM); + else if (self.thingtype==THINGTYPE_FLESH) + sound (self, CHAN_VOICE, "raven/fleshbrk.wav", 1, ATTN_NORM); + else if (self.thingtype==THINGTYPE_CLOTH) + sound (self, CHAN_VOICE, "raven/clothbrk.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "raven/wallbrk.wav", 1, ATTN_NORM); + + // FIXME: are we adding sprites to the deaths also??? +// while (spritecount>0) +// { +// CreateSpriteChunks(space); +// spritecount = spritecount - 1; +// } + + while (chunkcount>0) + { + CreateModelChunks(space); + chunkcount = chunkcount - 1; + } + + SUB_UseTargets(); + + remove(self); +}; + diff --git a/global.hc b/global.hc new file mode 100644 index 0000000..9560b00 --- /dev/null +++ b/global.hc @@ -0,0 +1,175 @@ + +//************************************************************************** +//** +//** global.hc +//** +//** $Header: /HexenWorld/Siege/global.hc 13 5/25/98 1:38p Mgummelt $ +//** +//************************************************************************** + +// SYSTEM GLOBALS (globalvars_t C structure) ------------------------------- + +entity self; +entity other; +entity world; +float time; +float frametime; + +entity newmis; // if this is set, the entity that just + // run created a new missile that should + // be simulated immediately + +// Force all entities to touch triggers next frame. This is needed +// because non-moving things don't normally scan for triggers, and +// when a trigger is created (like a teleport trigger), it needs to +// catch everything. Decremented each frame, so set to 2 to guarantee +// everything is touched. +float force_retouch; + +string mapname; +string startspot; + +float deathmatch; +float randomclass; +float damageScale; +float meleeDamScale;//amount to scale damage when victim has melee weapon currently selected +float shyRespawn; +float spartanPrint; +float manaScale; +float tomeMode; +float tomeRespawn; +float w2Respawn; +float altRespawn; +float fixedLevel; +float autoItems; +float dmMode; +float easyFourth; +float patternRunner; +float coop; +float teamplay; + +// Propagated from level to level, used to keep track of completed +// episodes. +float serverflags; + +float total_secrets; +float total_monsters; + +// Number of secrets found. +float found_secrets; + +// Number of monsters killed. +float killed_monsters; +float chunk_cnt; // # of chunks currently existing (don't want to exceed max) + +// Set by monster spawner to make sure monster init functions don't +// precache models after level is started. +float done_precache; + +// Spawnparms are used to encode information about clients across server +// level changes. +float parm1, parm2, parm4, parm5, parm6, parm7, parm8, + parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16; + +string parm3; + +// Set by makevectors() +vector v_forward, v_up, v_right; + +// Set by traceline(). +float trace_allsolid; +float trace_startsolid; +float trace_fraction; +vector trace_endpos; +vector trace_plane_normal; +float trace_plane_dist; +entity trace_ent; +float trace_inopen; +float trace_inwater; + +// Destination of single entity writes. +entity msg_entity; + +// Set by OP_CSTATE ([++ $s..$e], [-- $s..$e]). +float cycle_wrapped; + +float crouch_cnt; + +float modelindex_assassin; +float modelindex_crusader; +float modelindex_paladin; +float modelindex_necromancer; +float modelindex_sheep; + +float num_players; +float exp_mult; +float max_players; +float defLosses; +float attLosses; + +// REQUIRED FUNCTIONS ------------------------------------------------------ + +// Only for testing +void main(void); + +void StartFrame(void); +void PlayerPreThink(void); +void PlayerPostThink(void); +void ClientKill(void); +void ClientConnect(void); +void PutClientInServer(void); +void ClientReEnter(float TimeDiff); +void ClientDisconnect(void); +void ClassChangeWeapon(void); + +void SetNewParms(void); // called when a client first connects to + // a server. sets parms so they can be + // saved off for restarts + +void SetChangeParms(void); // call to set parms for self so they can + // be saved for a level transition + +void SmitePlayer(); // Server smites a player + +// END SYSTEM GLOBALS ------------------------------------------------------ + +// Flag the compiler. +void end_sys_globals; + +float movedist; + +// Set when a rule exits. +float gameover; + +// NULL string, nothing should be held here. +string string_null; + +// Function launch_spike() sets this after spawning it. +entity newmis; + +// The entity that activated a trigger or brush. +entity activator; + +// Set by T_Damage(). +entity damage_attacker; + +float framecount; + +float skill; + +float wp_deselect; // A flag showing a weapon is being deselected ignore impulse 10 + +entity print_ent1; +entity print_ent2; +string nextmap; + +float START_LIT; + +float g_timelimit; +float g_init_timelimit; +float g_fraglimit; +string g_keyname; +string g_keymdl; +float gamestarted; +float newsiege; + diff --git a/glyph.hc b/glyph.hc new file mode 100644 index 0000000..1db31a2 --- /dev/null +++ b/glyph.hc @@ -0,0 +1,68 @@ +/* + * $Header: /HexenWorld/Siege/glyph.hc 3 5/25/98 1:38p Mgummelt $ + */ + +void (float explodetype) BecomeExplosion ; + +void () TouchGlyph = +{ + local float damg; + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_EXPLOSION); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + + BecomeExplosion (FALSE); + + damg = GLYPH_BASE_DAMAGE + random(GLYPH_ADD_DAMAGE); + + self.owner = self; + + if (other.health) + T_Damage (other, self, self.owner, damg ); + + // don't do radius damage to the other, because all the damage + // was done in the impact + T_RadiusDamage (self, self.owner, damg, other); + T_RadiusManaDamage (self, self.owner, damg, other); + + remove(self); +}; + +void () DecrementGlyph = +{ + + if (self.lifetime > time) + { + self.nextthink = time + 1; + return; + } + else + TouchGlyph (); + +}; + +void () Use_Glyph = +{ + local entity glyph; + + glyph = spawn(); + + glyph.owner = self; + +// precache_model("models/glyph.mdl"); + CreateEntityNew(self,ENT_GLYPH,"models/glyph.mdl",SUB_Null); + + glyph.touch = TouchGlyph; + glyph.classname = "running_glyph"; + + setorigin (glyph, self.origin); + + glyph.think = DecrementGlyph; + glyph.nextthink = time + 1; + glyph.lifetime = time + 10; + +}; + diff --git a/golem.hc b/golem.hc new file mode 100644 index 0000000..86331ad --- /dev/null +++ b/golem.hc @@ -0,0 +1,1436 @@ + +//************************************************************************** +//** +//** golem.hc +//** +//** $Header: /HexenWorld/Siege/golem.hc 4 5/25/98 1:38p Mgummelt $ +//** +//************************************************************************** + +// FRAMES ------------------------------------------------------------------ +// Common: Rest +$frame rest1 rest2 rest3 rest4 rest5 rest6 rest7 rest8 rest9 rest10 +$frame rest11 rest12 rest13 rest14 rest15 rest16 rest17 rest18 rest19 +$frame rest20 rest21 rest22 + +// Common: Transition from run to rest +$frame transa1 transa2 transa3 transa4 transa5 transa6 transa7 transa8 +$frame transa9 transa10 transa11 transa12 transa13 + +// Common: Transition from rest to run +$frame transb1 transb2 transb3 transb4 transb5 transb6 transb7 transb8 +$frame transb9 transb10 transb11 transb12 transb13 + +// Common: Transition from still to run +$frame wake1 wake2 wake3 wake4 wake5 wake6 wake7 wake8 wake9 wake10 +$frame wake11 wake12 wake13 wake14 wake15 wake16 + +// Common: Walk +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 walk13 walk14 walk15 walk16 walk17 walk18 walk19 +$frame walk20 walk21 walk22 walk23 walk24 walk25 walk26 walk27 walk28 +$frame walk29 walk30 walk31 walk32 walk33 walk34 + +// Common: Run +$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12 +$frame run13 run14 run15 run16 run17 run18 run19 run20 run21 run22 +$frame run23 run24 + +// Common: Right hand punch attack +$frame rpunch1 rpunch2 rpunch3 rpunch4 rpunch5 rpunch6 rpunch7 rpunch8 +$frame rpunch9 rpunch10 rpunch11 rpunch12 rpunch13 rpunch14 rpunch15 +$frame rpunch16 rpunch17 rpunch18 rpunch19 rpunch20 rpunch21 +$frame rpunch22 rpunch23 rpunch24 + +// Common: Right hand pound attack +$frame rpound1 rpound2 rpound3 rpound4 rpound5 rpound6 rpound7 rpound8 +$frame rpound9 rpound10 rpound11 rpound12 rpound13 rpound14 rpound15 +$frame rpound16 rpound17 rpound18 rpound19 rpound20 rpound21 +$frame rpound22 rpound23 rpound24 + +// Common: Death +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 +$frame death10 death11 death12 death13 death14 death15 death16 death17 +$frame death18 death19 death20 +$frame death21 death22 + +$framesave x + +// Stone: Charge at the player +$frame rush1 rush2 rush3 rush4 rush5 rush6 rush7 rush8 rush9 rush10 +$frame rush11 rush12 rush13 rush14 rush15 rush16 rush17 rush18 rush19 +$frame rush20 rush21 rush22 rush23 rush24 + +$framerestore x + +// Iron: Gem attack +$frame igem1 igem2 igem3 igem4 igem5 igem6 igem7 igem8 igem9 igem10 +$frame igem11 igem12 igem13 igem14 igem15 igem16 igem17 igem18 igem19 +$frame igem20 igem21 igem22 igem23 igem24 + +$framerestore x + +// Bronze: Gem attack +$frame bgem1 bgem2 bgem3 bgem4 bgem5 bgem6 bgem7 bgem8 bgem9 bgem10 +$frame bgem11 bgem12 bgem13 bgem14 bgem15 bgem16 bgem17 bgem18 bgem19 +$frame bgem20 bgem21 bgem22 bgem23 bgem24 + +// Bronze: Stomp attack +$frame stomp1 stomp2 stomp3 stomp4 stomp5 stomp6 stomp7 stomp8 stomp9 +$frame stomp10 stomp11 stomp12 stomp13 stomp14 stomp15 stomp16 stomp17 +$frame stomp18 stomp19 stomp20 stomp21 stomp22 stomp23 stomp24 + +// CONSTANTS --------------------------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +void GolemInit(void); +void GolemCUse(void); +void GolemStand(void); +void GolemWalk(void); +void GolemRun(void); +void GolemSMeleeDecide(void); +void GolemIMeleeDecide(void); +void GolemBMeleeDecide(void); +void GolemPunchRight(void); +void GolemPoundRight(void); +void GolemSRushBegin(void); +void GolemSRushSlide(void); +void GolemSRushEnd(void); +float GolemFlinch(float firstFrame, float lastFrame); +void GolemSPain(void); +void GolemIPain(void); +void GolemBPain(void); +void GolemDie(void); +void GolemBBeamBegin(void); +void GolemBStomp(void); +void GolemIMissile(void); +float GolemBCheckBeamAttack(); +float GolemICheckMissileAttack(); + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// monster_golem_stone +// +//========================================================================== +/*QUAKED monster_golem_stone (1 0.3 0) (-32 -32 0) (32 32 88) AMBUSH +Stone Golem. +------- key / value ---------------------------- +health = 200 +experience_value = 125 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_golem_stone(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + precache_model3("models/golem_s.mdl"); + + precache_model3("models/goarm.mdl"); + precache_model3("models/golegs.mdl"); + precache_model3("models/g-head.mdl"); + + precache_sound3("golem/stnfall.wav"); + precache_sound3("golem/stnpain.wav"); + precache_sound3("golem/slide.wav"); + precache_sound3("imp/swoophit.wav"); + precache_sound3("golem/dthgroan.wav"); + + self.thingtype = THINGTYPE_GREYSTONE; + setmodel(self, "models/golem_s.mdl"); + setsize(self, '-24 -24 0', '24 24 80'); + GolemInit(); + self.hull = HULL_PLAYER; + self.health = 200; + self.experience_value = 125; + self.mintel = 4; + self.th_melee = GolemSMeleeDecide; + self.th_pain = GolemSPain; + self.view_ofs = self.proj_ofs='0 0 64'; + walkmonster_start(); +} + +//========================================================================== +// +// monster_golem_iron +// +//========================================================================== +/*QUAKED monster_golem_iron (1 0.3 0) (-55 -55 0) (55 55 120) AMBUSH +Iron Golem. +------- key / value ---------------------------- +health = 400 +experience_value = 200 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_golem_iron(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + + precache_model2("models/golem_i.mdl"); + + precache_model2("models/goarm.mdl"); + precache_model2("models/golegs.mdl"); + precache_model2("models/g-head.mdl"); + + precache_model2("models/golemmis.mdl"); + precache_sound2("golem/mtlfall.wav"); + precache_sound2("golem/mtlpain.wav"); + precache_sound5("golem/gbfire.wav"); + precache_sound2("golem/dthgroan.wav"); + self.thingtype = THINGTYPE_METAL; + setmodel(self, "models/golem_i.mdl"); + setsize(self, '-32 -32 0', '32 32 80'); + GolemInit(); + self.health = 450; + self.mintel = 6; + self.experience_value = 200; + self.th_melee = GolemIMeleeDecide; + self.th_pain = GolemIPain; + self.view_ofs = self.proj_ofs='0 0 64'; + walkmonster_start(); +} + +//========================================================================== +// +// monster_golem_bronze +// +//========================================================================== +/*QUAKED monster_golem_bronze (1 0.3 0) (-64 -64 0) (64 64 194) AMBUSH +Bronze Golem. +------- key / value ---------------------------- +health = 500 +experience_value = 275 +------- spawnflags ----------------------------- +AMBUSH +*/ +void monster_golem_bronze(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + self.cnt = 0; + precache_model2("models/golem_b.mdl"); + + precache_model2("models/goarm.mdl"); + precache_model2("models/golegs.mdl"); + precache_model2("models/g-head.mdl"); + + precache_sound2("golem/mtlfall.wav"); + precache_sound2("golem/mtlpain.wav"); + precache_sound2("golem/stomp.wav"); + precache_sound2("golem/gbcharge.wav"); + precache_sound5("golem/gbfire.wav"); + precache_sound2("golem/dthgroan.wav"); + self.thingtype = THINGTYPE_METAL; + setmodel(self, "models/golem_b.mdl"); + setsize(self, '-60 -60 0', '60 60 190'); + GolemInit(); + self.health = 650; + self.mintel = 8; + self.experience_value = 275; + self.th_melee = GolemBMeleeDecide; + self.th_pain = GolemBPain; + self.view_ofs = self.proj_ofs='0 0 115'; + walkmonster_start(); +} + +//========================================================================== +// +// monster_golem_crystal +// +//========================================================================== +/*QUAKED monster_golem_crystal (1 0.3 0) (-32 -32 -24) (32 32 64) AMBUSH +Crystal Golem. +------- key / value ---------------------------- +health = 400 +experience_value = 650 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_golem_crystal(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + precache_model3("models/golem_s.mdl"); + precache_sound3("golem/stnpain.wav"); + precache_sound3("golem/slide.wav"); + precache_sound3("golem/dthgroan.wav"); + self.thingtype = THINGTYPE_ICE; + setmodel(self, "models/golem_s.mdl"); + setsize(self, '-24 -24 0', '24 24 80'); + GolemInit(); + self.hull = HULL_PLAYER; + self.drawflags = DRF_TRANSLUCENT|MLS_ABSLIGHT; + self.abslight = 1.4; + self.skin = GLOBAL_SKIN_ICE; + self.health = 400; + self.experience_value = 650; + self.th_melee = GolemSMeleeDecide; + self.th_pain = GolemSPain; + self.use = GolemCUse; + + self.view_ofs = self.proj_ofs='0 0 64'; + + walkmonster_start(); + + self.takedamage = DAMAGE_NO; +} + +//========================================================================== +// +// GolemInit +// +//========================================================================== + +void GolemInit(void) +{ + self.netname="golem"; + self.flags (+) FL_MONSTER; + self.flags2 (+) FL_ALIVE; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.yaw_speed = 14; + self.mass = 75; + self.mintel = 2; + self.hull = HULL_GOLEM; + self.th_stand = GolemStand; + self.th_walk = GolemWalk; + self.th_run = GolemRun; + self.th_die = GolemDie; + precache_sound3("golem/awaken.wav"); + precache_sound3("golem/step.wav"); + precache_sound3("golem/swing.wav"); +} + +//========================================================================== +// +// GolemCUse +// +//========================================================================== + +void GolemCUse(void) +{ + self.takedamage = DAMAGE_YES; + self.drawflags = DRF_TRANSLUCENT|MLS_CRYSTALGOLEM; +} + +//========================================================================== +// +// GolemStand +// +//========================================================================== + +void GolemStand(void) [++ $rest1..$rest22] +{ + ai_stand(); + thinktime self : 0.2; +} + +//========================================================================== +// +// GolemWalk +// +//========================================================================== + +void GolemWalk(void) [++ $walk1..$walk34] +{ + if(self.frame == $walk16 || self.frame == $walk33) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } + ai_walk(2); +} + +//========================================================================== +// +// GolemRun +// +//========================================================================== + +void GolemRun(void) [++ $run1..$run24] +{ + float len; + float hdiff; + float dist, r; + + check_pos_enemy(); + checkenemy(); + + if (coop && !visible(self.enemy)) + LocateTarget(); + + if (self.classname == "monster_golem_stone" || self.classname == "monster_golem_crystal") + { + len = vlen(self.origin - self.enemy.origin); + hdiff = fabs(self.origin_z - self.enemy.origin_z); + if(len > 50 && len < 300 && hdiff < 80) + { + if(random() < 0.05) + { + GolemSRushBegin(); + return; + } + } + ai_run(8); + } + + if (self.classname == "monster_golem_bronze") + { + dist = vlen(self.enemy.origin - self.origin); + r = random(0, 10); + + if (dist < 100) + GolemBMeleeDecide(); + else if (dist > 256 && visible(self.enemy) && r < 0.6) + { + if (GolemBCheckBeamAttack() == 1) + GolemBBeamBegin(); + } + else if (dist > 100 && dist < 256 && r < 0.3) + GolemBStomp(); + + ai_run(8); + } + + if (self.classname == "monster_golem_iron") + { + dist = vlen(self.enemy.origin - self.origin); + r = random(0, 10); + + if (dist < 100) + GolemBMeleeDecide(); + else if (dist > 100 && visible(self.enemy) && r < 0.4) + if (GolemICheckMissileAttack()) + GolemIMissile(); + + ai_run(5); + } + + + if(self.frame == $run12 || self.frame == $run24) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } +} + +void GolemDoMelee(float critical) +{ +vector delta; +float ldmg; + + if (!self.enemy) + return; // removed before stroke + + delta = self.enemy.origin - self.origin; + + if (self.classname == "monster_golem_bronze") + { + if (vlen(delta) > 128) + return; + ldmg = random(15); + } + else if (self.classname == "monster_golem_iron") + { + if (vlen(delta) > 128) + return; + ldmg = random(12); + } + else + { + ldmg = random(8); + if (vlen(delta) > 128) return; + } + + if (critical) ldmg = ldmg * 1.5; + + if (self.attack_finished < time) + { + sound(self, CHAN_BODY, "imp/swoophit.wav", 1, ATTN_NORM); + self.attack_finished = time + 1; + } + + if (self.enemy.health - ldmg <= 0 && critical&&self.enemy.flags2&FL_ALIVE) + self.enemy.decap = 2; + + T_Damage (self.enemy, self, self, ldmg); +} + +//========================================================================== +// +// GolemSMeleeDecide +// +//========================================================================== + +void GolemSMeleeDecide(void) +{ + if(random() < 0.5) + { + GolemPunchRight(); + } + else + { + GolemPoundRight(); + } +} + +void GolemIMissileTouch(void) +{ + if (other.health > 0 && other.flags & FL_ALIVE) + T_Damage(other, self, self.owner, random(13,17)); + + remove(self); +} + +void GolemIMissileThink(void) +{ + if (self.count > time) + HomeThink(); + + particle4(self.origin,20,random(128,143),PARTICLETYPE_GRAV,4); + + self.angles = vectoangles(self.velocity); + + self.think = GolemIMissileThink; + thinktime self : 0.1; +} + +void GolemISpawnMissile(vector vect, vector offset, float vel) +{ + local entity missile; + local vector vec; + + self.last_attack=time; + missile = spawn (); + missile.classname = "golem_iron_proj"; + missile.owner = self; + missile.enemy = missile.goalentity = self.enemy; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.yaw_speed = 3; + missile.drawflags (+) MLS_POWERMODE | SCALE_TYPE_UNIFORM; + missile.scale = 2.5; + + + setmodel (missile, "models/golemmis.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + + // set missile speed + + makevectors (self.angles); + setorigin (missile, self.origin + offset); + + vec = self.enemy.origin - missile.origin + self.enemy.view_ofs; + + vec = normalize(vec); + + vec += vect; + + missile.speed = 300; + missile.velocity = vec * (300 - random(vel)); + missile.angles = vectoangles(missile.velocity); + + missile.touch = GolemIMissileTouch; + + missile.think = GolemIMissileThink; + + missile.veer=0; //slight veering, random course modifications + missile.turn_time = 0.5; + missile.hoverz=TRUE; //slow down on turns + missile.ideal_yaw=TRUE; + + missile.count = time + 2; + + thinktime missile : 0.2; +} + +void GolemIMissile(void) [++ $igem1..$igem24] +{ + vector vect; + + ai_face(); + + makevectors(self.angles); + + if (self.frame == $igem1) + self.colormap = 128 + 16; + + if (self.frame == $igem1) + { + vect = self.origin + (v_forward * 16); + particle4(vect + '0 0 90',15,256+random(128,143),PARTICLETYPE_GRAV,10); + } + + self.colormap -= 0.5; + + if (self.frame == $igem17 && FacingIdeal()) + { + sound(self, CHAN_WEAPON, "golem/gbfire.wav", 1, ATTN_NORM); + //GolemISpawnMissile(v_right * -1, '0 0 75', 20); + + GolemISpawnMissile('0 0 0', '0 0 75', 100); + /*GolemISpawnMissile(v_right, '0 0 75', 20); + GolemISpawnMissile(v_up * -1, '0 0 75', 20); + GolemISpawnMissile(v_up, '0 0 75', 20);*/ + + self.think = self.th_run; + self.colormap = 0; + thinktime self : 0.1; + } + +} + +//========================================================================== +// +// GolemIMeleeDecide +// +//========================================================================== + +void GolemIMeleeDecide(void) +{ + if(random() < 0.5) + { + GolemPunchRight(); + } + else + { + GolemPoundRight(); + } +} + +//========================================================================== +// +// GolemBMeleeDecide +// +//========================================================================== + +void GolemBMeleeDecide(void) +{ + if(random() < 0.5) + { + GolemPunchRight(); + } + else + { + GolemPoundRight(); + } +} + +//========================================================================== +// +// GolemPunchRight +// +//========================================================================== + +void GolemPunchRight(void) [++ $rpunch1..$rpunch24] +{ + vector checkPos; + + if(cycle_wrapped) + { + GolemRun(); + return; + } + if(self.frame == $rpunch10) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + sound(self, CHAN_WEAPON, "golem/swing.wav", 1, ATTN_NORM); + } + else if(self.frame == $rpunch24) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } + //ai_charge(8); + ai_face(); + + if (!walkmove(self.angles_y, 8, TRUE)) + { + if (trace_ent.health <= 0) return; + } + + if(self.frame > $rpunch10 && self.frame < $rpunch16) + { + makevectors(self.enemy.angles); + + checkPos = self.enemy.origin + (v_forward * -24); + checkPos_z = self.enemy.origin_z + self.enemy.view_ofs_z; + + traceline(self.enemy.origin, checkPos, FALSE, self.enemy); + + + if (trace_fraction < 1&&!trace_ent.flags2&FL_ALIVE) + GolemDoMelee(1); + else + GolemDoMelee(0); + } +} + +//========================================================================== +// +// GolemPoundRight +// +//========================================================================== + +void GolemPoundRight(void) [++ $rpound1..$rpound24] +{ + vector checkPos; + + if(cycle_wrapped) + { + GolemRun(); + return; + } + if(self.frame == $rpound10) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + sound(self, CHAN_WEAPON, "golem/swing.wav", 1, ATTN_NORM); + } + else if(self.frame == $rpound24) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } + + ai_face(); + + if (!walkmove(self.angles_y, 10, TRUE)) + { + if (trace_ent.health <= 0) return; + } + + if(self.frame > $rpound10 && self.frame < $rpound16) + { + makevectors(self.enemy.angles); + + checkPos = self.enemy.origin + (v_forward * -24); + checkPos_z = self.enemy.origin_z + self.enemy.view_ofs_z; + + traceline(self.enemy.origin, checkPos, FALSE, self.enemy); + + + if (trace_fraction < 1) + GolemDoMelee(1); + else + GolemDoMelee(0); + } +} + +//========================================================================== +// +// GolemSRushBegin +// +//========================================================================== + +void GolemSRushBegin(void) [++ $rush1..$rush12] +{ + if(self.frame == $rush12) + { + self.golemSlideCounter = 8; + self.think = GolemSRushSlide; + sound(self, CHAN_WEAPON, "golem/slide.wav", 1, ATTN_NORM); + } + else if(self.frame == $rush10) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } + //ai_charge(5); + ai_face(); + + if (!walkmove(self.angles_y, 5, TRUE)) + { + if (trace_ent.health <= 0) return; + } + +} + +//========================================================================== +// +// GolemSRushSlide +// +//========================================================================== + +void GolemSRushSlide(void) [$rush12 GolemSRushSlide] +{ + if(walkmove(self.angles_y, 20, FALSE)) + { + if(random() < 0.2) + { + CreateWhiteSmoke(self.origin,'0 0 8',HX_FRAME_TIME * 2); + } + } + else + { + self.think = GolemSRushEnd; + return; + } + self.golemSlideCounter -= 1; + if(self.golemSlideCounter < 0) + { + self.think = GolemSRushEnd; + } +} + +float GolemBCheckBeamAttack(void) +{ + vector p1, p2, off; + float dist; + + makevectors(self.angles); + + dist = vlen(self.enemy.origin - self.origin); + + off = v_forward * 15 + v_right * 1; + p1 = self.origin + '0 0 92' + off; + + p2 = p1 + (v_forward * dist); + p2_z = self.enemy.origin_z + self.enemy.proj_ofs_z; + + traceline(p1, p2, FALSE, self); + + if (trace_ent == self.enemy) + return 1; + + return 0; +} + +float GolemICheckMissileAttack(void) +{ + vector p1, p2, off; + float dist; + + makevectors(self.angles); + + dist = vlen(self.enemy.origin - self.origin); + + off = v_forward * 15 + v_right * 1; + p1 = self.origin + '0 0 92' + off; + + p2 = p1 + (v_forward * dist); + p2_z = self.enemy.origin_z + self.enemy.proj_ofs_z; + + traceline(p1, p2, FALSE, self); + + if (trace_ent == self.enemy) + return 1; + + return 0; +} + +void GolemBBeamFinish(void) [++ $bgem18..$bgem24] +{ + if (self.frame == $bgem24) + { + self.colormap = 0; + self.think = self.th_run; + thinktime self : 0.1; + return; + } +} + +void GolemDoBeam(float offset, float damage) +{ + vector p1, p2, off, dir; + float dist; + + makevectors(self.angles); + + dist = vlen(self.enemy.origin - self.origin); + + off = v_forward * 15 + v_right * 1; + p1 = self.origin + '0 0 92' + off; + + dist = vlen(p1 - self.enemy.origin + self.enemy.proj_ofs - '0 0 6'); + + /*p2 = p1 + (v_forward * dist + v_right * offset); + p2_z = self.enemy.origin_z + self.enemy.proj_ofs_z;*/ + + dir = normalize(v_forward*100 + v_right * offset); + p2 = p1 + dir*dist; + p2_z = self.enemy.origin_z + self.enemy.proj_ofs_z - 6; + + dir = normalize(p2-p1); + traceline(p1, p2+dir*(dist/2), FALSE, self); + + //traceline(p1, p2, FALSE, self); + + if (trace_ent != world && trace_ent.health > 0) + { + sound(trace_ent,CHAN_AUTO,"crusader/sunhit.wav",1,ATTN_NORM); + + if (trace_ent.health - damage <= 0) + trace_ent.decap = TRUE; + + if (trace_ent.flags & FL_MONSTER) + T_Damage(trace_ent,self,self,damage/2); + else + T_Damage(trace_ent,self,self,damage); + } + + SpawnPuff(trace_endpos, '0 0 10', 1, trace_ent); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_STREAM_COLORBEAM); //beam type + WriteEntity (MSG_BROADCAST, self); //owner + WriteByte (MSG_BROADCAST, 0); //tag + flags + WriteByte (MSG_BROADCAST, 1); //time + WriteByte (MSG_BROADCAST, 2); //color + + WriteCoord (MSG_BROADCAST, p1_x); + WriteCoord (MSG_BROADCAST, p1_y); + WriteCoord (MSG_BROADCAST, p1_z); + + WriteCoord (MSG_BROADCAST, trace_endpos_x); + WriteCoord (MSG_BROADCAST, trace_endpos_y); + WriteCoord (MSG_BROADCAST, trace_endpos_z); +} + +void GolemBBeamFireArch1(void) [$bgem18 GolemBBeamFireArch1] +{ + if (self.golemBeamDelay < time) + { + self.think = GolemBBeamFinish; + thinktime self : 0.1; + return; + } + + self.golemBeamOff1 += 5; + + GolemDoBeam(self.golemBeamOff1, random(7, 12)); +} + +void GolemBBeamFireArch2(void) [$bgem18 GolemBBeamFireArch2] +{ + if (self.golemBeamDelay < time) + { + self.think = GolemBBeamFinish; + thinktime self : 0.1; + return; + } + + if (!self.golemBeamOff2) + self.golemBeamOff1 += 10; + else + self.golemBeamOff1 -= 10; + + + if (self.golemBeamOff1 == 100) + self.golemBeamOff2 = 1; + + GolemDoBeam(self.golemBeamOff1, random(7, 12)); +} + +void GolemBBeamFire(void) [++ $bgem11..$bgem18] +{ + float r; + + ai_face(); + + if (self.frame == $bgem18) + { + r = random(); + + if (visible(self.enemy) && FacingIdeal()) + { + sound(self, CHAN_WEAPON, "golem/gbfire.wav", 1, ATTN_NORM); + + if (r < 0.5) + { + self.golemBeamDelay = time + 2; + self.golemBeamOff1 = -100; + self.think = GolemBBeamFireArch1; + thinktime self : 0.1; + } + else + { + self.golemBeamDelay = time + 2; + self.golemBeamOff1 = -100; + self.golemBeamOff2 = 0; + self.think = GolemBBeamFireArch2; + thinktime self : 0.1; + } + } + else + { + self.think = self.th_run; + thinktime self : 0.1; + } + } +} + +void GolemBBeamPause(void) [$bgem11 GolemBBeamPause] +{ + if (self.golemBeamDelay < time && !self.cnt) + { + self.golemBeamDelay = time + 0.5; + self.cnt = 1; + self.colormap = 176 + 16; + } + + self.colormap -= 1; + + if (self.golemBeamDelay > time) + { + particle4(self.origin + self.view_ofs,5,185 + random(6),PARTICLETYPE_SLOWGRAV,1); + ai_face(); + return; + } + + self.cnt = 0; + GolemBBeamFire(); +} + +//========================================================================== +// +// GolemBBeam +// +//========================================================================== + +void GolemBBeamBegin(void) [++ $bgem1..$bgem11] +{ + sound(self, CHAN_WEAPON, "golem/gbcharge.wav", 1, ATTN_NORM); + + if (self.frame == $bgem11) + { + thinktime self : 0.1; + self.think = GolemBBeamPause; + } +} + +void GolemBStompEffect(void) +{ + float dist; + + dist = vlen(self.enemy.origin - self.origin); + + MonsterQuake(350); + + if (dist < 350) + T_Damage(self.enemy, self, self, random(50/dist)); +} + +//========================================================================== +// +// GolemBStomp +// +//========================================================================== + +void GolemBStomp(void) [++ $stomp1..$stomp24] +{ + float numPuffs; + vector vect; + + if (self.frame == $stomp13) + { + sound(self, CHAN_BODY, "golem/stomp.wav", 1, ATTN_NORM); + numPuffs = random(4,10); + + makevectors(self.angles); + + while(numPuffs > 0) + { + vect_x = self.origin_x; + vect_y = self.origin_y; + vect_z = self.absmin_z; + + vect_z += v_up_z * 3; + vect_x += v_forward_x * random(0, self.size_x); + vect_y += v_forward_y * random(0, self.size_y); + + particle4(vect,20+random(1,10),256+random(90, 95),PARTICLETYPE_GRAV,30); + numPuffs -= 1; + } + GolemBStompEffect(); + } + + if (self.frame == $stomp24) + { + self.think = self.th_run; + thinktime self : 0.1; + } +} + +void GolemICheckRushDamage( void ) +{ + float r; + float damage; + + if(!self.enemy) + return; + + r = vlen(self.enemy.origin - self.origin); + + damage = random(20,30); + + + if (infront(self.enemy) && r < 60) + { + sound(self, CHAN_BODY, "imp/swoophit.wav", 1, ATTN_NORM); + + makevectors(self.angles); + + self.enemy.flags (-) FL_ONGROUND; + self.enemy.velocity = (v_forward * (damage * 20)); + self.enemy.velocity_z = random(300, 350); + + T_Damage(self.enemy, self, self, damage); + } +} + +//========================================================================== +// +// GolemSRushEnd +// +//========================================================================== + +void GolemSRushEnd(void) [++ $rush13..$rush24] +{ + if(cycle_wrapped) + { + GolemRun(); + return; + } + + if (self.frame == $rush15) + { + GolemICheckRushDamage(); + } + + if(self.frame == $rush24) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } + //ai_charge(4); + ai_face(); + + if (!walkmove(self.angles_y, 4, TRUE)) + { + if (trace_ent.health <= 0) return; + } +} + +//========================================================================== +// +// GolemFlinch +// +//========================================================================== + +float GolemFlinch(float firstFrame, float lastFrame) +{ + if(self.frame < firstFrame || self.frame > lastFrame) + { + return 0; + } + self.nextthink += 0.1+random()*0.2; + self.frame = self.frame - 8 - rint(random() * 12); + self.pain_finished = time + 1; + if(self.frame < firstFrame) + { // Wrap + self.frame = lastFrame + 1 - (firstFrame - self.frame); + } + return 1; +} + +//========================================================================== +// +// GolemSPain +// +//========================================================================== + +void GolemSPain(void) +{ + if(self.pain_finished > time) + { + return; + } + //if(GolemFlinch($gwalk1, $gwalk60)) return; + //if(GolemFlinch($gLpnch1, $gLpnch22)) return; + //if(GolemFlinch($gRpnch1, $gRpnch22)) return; + + //GolemFlinch($run1, $run24); +} + +//========================================================================== +// +// GolemIPain +// +//========================================================================== + +void GolemIPain(void) +{ + if(self.pain_finished > time) + { + return; + } + //if(GolemFlinch($gwalk1, $gwalk60)) return; + //if(GolemFlinch($ggem1, $ggem25)) return; + //if(GolemFlinch($gRpnch1, $gRpnch22)) return; + + //GolemFlinch($run1, $run24); +} + +//========================================================================== +// +// GolemBPain +// +//========================================================================== + +void GolemBPain(void) +{ + if(self.pain_finished > time) + { + return; + } + //if(GolemFlinch($gwalk1, $gwalk60)) return; + //if(GolemFlinch($ggem1, $ggem25)) return; + //if(GolemFlinch($gLpnch1, $gLpnch22)) return; + //if(GolemFlinch($gRpnd1, $gRpnd20)) return; + + //GolemFlinch($run1, $run24); +} + +float GolemCheckSolidGround( void ) +{ + vector p1, p2, p3, p4, destin; + float numSolid = 4; + + makevectors(self.angles); + + p1 = self.origin + (v_forward * (self.size_y * 0.8)); + p2 = self.origin - (v_forward * (self.size_y * 0.8)); + p3 = self.origin + (v_right * (self.size_x * 0.5)); + p4 = self.origin - (v_right * (self.size_x * 0.5)); + + destin = p1 - (v_up * self.size_y); + traceline(p1, destin, FALSE, self); + if (trace_fraction == 1) numSolid -= 1; + + destin = p2 - (v_up * self.size_y); + traceline(p2, destin, FALSE, self); + if (trace_fraction == 1) numSolid -= 1; + + destin = p3 - (v_up * self.size_y); + traceline(p3, destin, FALSE, self); + if (trace_fraction == 1) numSolid -= 1; + + destin = p4 - (v_up * 2); + traceline(p4, destin, FALSE, self); + if (trace_fraction == 1) numSolid -= 1; + + if (numSolid < 3) + return 0; + + return 1; +} + + +void GolemChunkPlace(string gibname, vector pos, vector vel) +{ + local entity new; + + makevectors(self.angles); + + new = spawn(); + new.origin = pos; + setmodel (new, gibname); + setsize (new, '0 0 0', '0 0 0'); + + new.velocity = vel; + new.movetype = MOVETYPE_BOUNCE; + new.solid = SOLID_NOT; + new.angles = self.angles; + + if (gibname != "models/golegs.mdl") + { + new.avelocity_y = random(100,500); + + new.velocity_x += random(v_forward_x * 100,v_forward_x * 300); + new.velocity_y += random(v_forward_y * 100,v_forward_y * 300); + new.velocity_z += random(v_forward_z * 350,v_forward_z * 600); + + new.flags (-) FL_ONGROUND; + } + + if (self.classname == "monster_golem_crystal") + { + new.drawflags = DRF_TRANSLUCENT|MLS_ABSLIGHT; + new.abslight = 1.4; + new.skin = GLOBAL_SKIN_ICE; + } + if (self.classname == "monster_golem_stone") + new.skin = 0; + if (self.classname == "monster_golem_iron") + { + new.scale = 1.5; + new.skin = 1; + } + if (self.classname == "monster_golem_bronze") + { + new.scale = 2.0; + new.skin = 2; + } + + new.think = SUB_Remove; + new.ltime = time; + new.nextthink = time + 10 + random()*10; + new.frame = 0; + new.flags = 0; +} + +void GolemChunkDeath(void) +{ + float numPuffs; + vector vect, dir; + + makevectors(self.angles); + dir = v_right*random(150, 200); + dir_z = random(100, 300); + GolemChunkPlace("models/goarm.mdl", self.origin + (v_right * 16), dir); + + dir = v_right*random(150, 200)*-1; + dir_z = random(100, 300); + GolemChunkPlace("models/goarm.mdl", self.origin + (v_right * -16), dir); + + GolemChunkPlace("models/golegs.mdl", self.origin + (v_forward * -12), '0 0 0'); + GolemChunkPlace("models/g-head.mdl", self.origin + (v_forward * random(10, 20)), '0 0 250'); + numPuffs = random(4,10); + + while(numPuffs > 0) + { + vect = self.origin; + + vect_z += v_up_z * 4; + vect_x += v_forward_x * random(0, self.size_x); + vect_y += v_forward_y * random(0, self.size_y); + + particle4(vect,20+random(1,10),256+random(90, 95),PARTICLETYPE_GRAV,10); + numPuffs -= 1; + } + + if (self.classname == "monster_golem_crystal") + self.thingtype = THINGTYPE_ICE; + + self.think = chunk_death; + thinktime self: 0.1; +} + +void GolemDeathFinish(void) [++ $death12..$death22] +{ if(self.frame == $death22) + { + self.nextthink = -1; + if(self.classname == "monster_golem_stone" || self.classname == "monster_golem_crystal") + { + sound(self, CHAN_BODY, "golem/stnfall.wav", 1, ATTN_NORM); + } + else if(self.classname == "monster_golem_iron") + { + sound(self, CHAN_BODY, "golem/mtlfall.wav", 1, ATTN_NORM); + } + else + { // Assumed bronze + sound(self, CHAN_BODY, "golem/mtlfall.wav", 1, ATTN_NORM); + } + + + if (GolemCheckSolidGround()) + { + GolemChunkDeath(); + //MakeSolidCorpse(); + } + else + { + self.think = chunk_death; + thinktime self : 0.1; + } + + return; + } + + if(self.frame == $death16) + { + self.solid = SOLID_NOT; + } + + if (self.frame > $death16) + { + makevectors(self.angles); + self.origin += v_forward * 4; + } + + if(self.health < -50) + { + self.think = chunk_death; + } + + thinktime self : 0.07; +} + +void GolemDeathPause(void) [$death11 GolemDeathPause] +{ + vector vect; + + if ((self.cnt - time) == 1) + { + sound(self, CHAN_BODY, "golem/dthgroan.wav", 1, ATTN_NORM); + + if (self.classname == "monster_golem_bronze") + { + makevectors(self.angles); + vect = self.origin + (v_forward * (self.size_x / 2)); + particle4(vect + '0 0 80',15,256+random(184, 191),PARTICLETYPE_GRAV,10); + } + if (self.classname == "monster_golem_iron") + { + makevectors(self.angles); + vect = self.origin + (v_forward * (self.size_x / 2)); + particle4(vect + '0 0 70',15,256+random(128,143),PARTICLETYPE_GRAV,10); + } + } + + if (self.cnt < time) + GolemDeathFinish(); +} + +//========================================================================== +// +// GolemDie +// +//========================================================================== + +void GolemDie(void) [++ $death1..$death11] +{ + self.colormap = 0; + + if (self.frame == $death11) + { + if (self.classname == "monster_golem_bronze" || self.classname == "monster_golem_iron") + sound(self, CHAN_BODY, "golem/mtlpain.wav", 1, ATTN_NORM); + else + sound(self, CHAN_BODY, "golem/stnpain.wav", 1, ATTN_NORM); + + self.cnt = time + 1; + GolemDeathPause(); + } +} diff --git a/golem_b.hc b/golem_b.hc new file mode 100644 index 0000000..05361ed --- /dev/null +++ b/golem_b.hc @@ -0,0 +1,383 @@ + +//************************************************************************** +//** +//** golem_b.hc +//** +//** $Header: /HexenWorld/Siege/golem_b.hc 3 5/25/98 1:38p Mgummelt $ +//** +//** Bronze golem. +//** +//************************************************************************** + +// FRAMES ------------------------------------------------------------------ + +// Transition from still to attack stance +$frame gbirth1 gbirth2 gbirth3 gbirth4 gbirth5 +$frame gbirth6 gbirth7 gbirth8 gbirth9 gbirth10 +$frame gbirth11 gbirth12 + +// Death +$frame gdeath1 gdeath2 gdeath3 gdeath4 gdeath5 +$frame gdeath6 gdeath7 gdeath8 gdeath9 gdeath10 +$frame gdeath11 gdeath12 gdeath13 gdeath14 gdeath15 +$frame gdeath16 gdeath17 gdeath18 gdeath19 gdeath20 +$frame gdeath21 gdeath22 gdeath23 gdeath24 gdeath25 +$frame gdeath26 gdeath27 gdeath28 gdeath29 gdeath30 +$frame gdeath31 gdeath32 gdeath33 gdeath34 gdeath35 +$frame gdeath36 gdeath37 gdeath38 gdeath39 gdeath40 +$frame gdeath41 gdeath42 gdeath43 gdeath44 gdeath45 +$frame gdeath46 gdeath47 gdeath48 gdeath49 gdeath50 +$frame gdeath51 + +// Walking +$frame gwalk1 gwalk2 gwalk3 gwalk4 gwalk5 +$frame gwalk6 gwalk7 gwalk8 gwalk9 gwalk10 +$frame gwalk11 gwalk12 gwalk13 gwalk14 gwalk15 +$frame gwalk16 gwalk17 gwalk18 gwalk19 gwalk20 +$frame gwalk21 gwalk22 gwalk23 gwalk24 gwalk25 +$frame gwalk26 gwalk27 gwalk28 gwalk29 gwalk30 +$frame gwalk31 gwalk32 gwalk33 gwalk34 gwalk35 +$frame gwalk36 gwalk37 gwalk38 gwalk39 gwalk40 +$frame gwalk41 gwalk42 gwalk43 gwalk44 gwalk45 +$frame gwalk46 gwalk47 gwalk48 gwalk49 gwalk50 +$frame gwalk51 gwalk52 gwalk53 gwalk54 gwalk55 +$frame gwalk56 gwalk57 gwalk58 gwalk59 gwalk60 + +// Transition from attack stance to walking +$frame gtran1 gtran2 gtran3 gtran4 gtran5 +$frame gtran6 gtran7 gtran8 gtran9 gtran10 +$frame gtran11 gtran12 gtran13 gtran14 gtran15 +$frame gtran16 gtran17 gtran18 gtran19 gtran20 +$frame gtran21 gtran22 gtran23 gtran24 gtran25 +$frame gtran26 + + + +// Gem attack +$frame ggem1 ggem2 ggem3 ggem4 ggem5 +$frame ggem6 ggem7 ggem8 ggem9 ggem10 +$frame ggem11 ggem12 ggem13 ggem14 ggem15 +$frame ggem16 ggem17 ggem18 ggem19 ggem20 +$frame ggem21 ggem22 ggem23 ggem24 ggem25 + +// Left hand punch attack +$frame gLpnch1 gLpnch2 gLpnch3 gLpnch4 gLpnch5 +$frame gLpnch6 gLpnch7 gLpnch8 gLpnch9 gLpnch10 +$frame gLpnch11 gLpnch12 gLpnch13 gLpnch14 gLpnch15 +$frame gLpnch16 gLpnch17 gLpnch18 gLpnch19 gLpnch20 +$frame gLpnch21 gLpnch22 + +// Right hand pound attack +$frame gRpnd1 gRpnd2 gRpnd3 gRpnd4 gRpnd5 +$frame gRpnd6 gRpnd7 gRpnd8 gRpnd9 gRpnd10 +$frame gRpnd11 gRpnd12 gRpnd13 gRpnd14 gRpnd15 +$frame gRpnd16 gRpnd17 gRpnd18 gRpnd19 gRpnd20 + +// Stomp attack +$frame gstomp1 gstomp2 gstomp3 gstomp4 gstomp5 +$frame gstomp6 gstomp7 gstomp8 gstomp9 gstomp10 +$frame gstomp11 gstomp12 gstomp13 gstomp14 gstomp15 +$frame gstomp16 gstomp17 gstomp18 gstomp19 gstomp20 +$frame gstomp21 gstomp22 gstomp23 gstomp24 gstomp25 +$frame gstomp26 gstomp27 gstomp28 gstomp29 gstomp30 + +void GolemBMeleeDecide(void); +void GolemBPunchLeft(void); +void GolemBPoundRight(void); + +// CODE -------------------------------------------------------------------- + +void() golemb_gbirth1 = [ $gbirth1 , golemb_gbirth2 ] { }; +void() golemb_gbirth2 = [ $gbirth2 , golemb_gbirth3 ] { }; +void() golemb_gbirth3 = [ $gbirth3 , golemb_gbirth4 ] { }; +void() golemb_gbirth4 = [ $gbirth4 , golemb_gbirth5 ] { }; +void() golemb_gbirth5 = [ $gbirth5 , golemb_gbirth6 ] { }; +void() golemb_gbirth6 = [ $gbirth6 , golemb_gbirth7 ] { }; +void() golemb_gbirth7 = [ $gbirth7 , golemb_gbirth8 ] { }; +void() golemb_gbirth8 = [ $gbirth8 , golemb_gbirth9 ] { }; +void() golemb_gbirth9 = [ $gbirth9 , golemb_gbirth10 ] { }; +void() golemb_gbirth10 = [ $gbirth10 , golemb_gbirth11 ] { }; +void() golemb_gbirth11 = [ $gbirth11 , golemb_gbirth12 ] { }; +void() golemb_gbirth12 = [ $gbirth12 , golemb_gbirth1 ] { }; + +/* +void() golemb_ggem1 = [ $ggem1 , golemb_ggem2 ] { }; +void() golemb_ggem2 = [ $ggem2 , golemb_ggem3 ] { }; +void() golemb_ggem3 = [ $ggem3 , golemb_ggem4 ] { }; +void() golemb_ggem4 = [ $ggem4 , golemb_ggem5 ] { }; +void() golemb_ggem5 = [ $ggem5 , golemb_ggem6 ] { }; +void() golemb_ggem6 = [ $ggem6 , golemb_ggem7 ] { }; +void() golemb_ggem7 = [ $ggem7 , golemb_ggem8 ] { }; +void() golemb_ggem8 = [ $ggem8 , golemb_ggem9 ] { }; +void() golemb_ggem9 = [ $ggem9 , golemb_ggem10 ] { }; +void() golemb_ggem10 = [ $ggem10 , golemb_ggem11 ] { }; +void() golemb_ggem11 = [ $ggem11 , golemb_ggem12 ] { }; +void() golemb_ggem12 = [ $ggem12 , golemb_ggem13 ] { }; +void() golemb_ggem13 = [ $ggem13 , golemb_ggem14 ] { }; +void() golemb_ggem14 = [ $ggem14 , golemb_ggem15 ] { }; +void() golemb_ggem15 = [ $ggem15 , golemb_ggem16 ] { }; +void() golemb_ggem16 = [ $ggem16 , golemb_ggem17 ] { }; +void() golemb_ggem17 = [ $ggem17 , golemb_ggem18 ] { }; +void() golemb_ggem18 = [ $ggem18 , golemb_ggem19 ] { }; +void() golemb_ggem19 = [ $ggem19 , golemb_ggem20 ] { }; +void() golemb_ggem20 = [ $ggem20 , golemb_ggem21 ] { }; +void() golemb_ggem21 = [ $ggem21 , golemb_ggem22 ] { }; +void() golemb_ggem22 = [ $ggem22 , golemb_ggem23 ] { }; +void() golemb_ggem23 = [ $ggem23 , golemb_ggem24 ] { }; +void() golemb_ggem24 = [ $ggem24 , golemb_ggem25 ] { }; +void() golemb_ggem25 = [ $ggem25 , golemb_ggem1 ] { }; +*/ + +/* +void() golemb_gLpnch1 = [ $gLpnch1 , golemb_gLpnch2 ] { }; +void() golemb_gLpnch2 = [ $gLpnch2 , golemb_gLpnch3 ] { }; +void() golemb_gLpnch3 = [ $gLpnch3 , golemb_gLpnch4 ] { }; +void() golemb_gLpnch4 = [ $gLpnch4 , golemb_gLpnch5 ] { }; +void() golemb_gLpnch5 = [ $gLpnch5 , golemb_gLpnch6 ] { }; +void() golemb_gLpnch6 = [ $gLpnch6 , golemb_gLpnch7 ] { }; +void() golemb_gLpnch7 = [ $gLpnch7 , golemb_gLpnch8 ] { }; +void() golemb_gLpnch8 = [ $gLpnch8 , golemb_gLpnch9 ] { }; +void() golemb_gLpnch9 = [ $gLpnch9 , golemb_gLpnch10 ] { }; +void() golemb_gLpnch10 = [ $gLpnch10 , golemb_gLpnch11 ] { }; +void() golemb_gLpnch11 = [ $gLpnch11 , golemb_gLpnch12 ] { }; +void() golemb_gLpnch12 = [ $gLpnch12 , golemb_gLpnch13 ] { }; +void() golemb_gLpnch13 = [ $gLpnch13 , golemb_gLpnch14 ] { }; +void() golemb_gLpnch14 = [ $gLpnch14 , golemb_gLpnch15 ] { }; +void() golemb_gLpnch15 = [ $gLpnch15 , golemb_gLpnch16 ] { }; +void() golemb_gLpnch16 = [ $gLpnch16 , golemb_gLpnch17 ] { }; +void() golemb_gLpnch17 = [ $gLpnch17 , golemb_gLpnch18 ] { }; +void() golemb_gLpnch18 = [ $gLpnch18 , golemb_gLpnch19 ] { }; +void() golemb_gLpnch19 = [ $gLpnch19 , golemb_gLpnch20 ] { }; +void() golemb_gLpnch20 = [ $gLpnch20 , golemb_gLpnch21 ] { }; +void() golemb_gLpnch21 = [ $gLpnch21 , golemb_gLpnch22 ] { }; +void() golemb_gLpnch22 = [ $gLpnch22 , golem_run_init ] { }; +*/ + +/* +void() golemb_gRpnd1 = [ $gRpnd1 , golemb_gRpnd2 ] { }; +void() golemb_gRpnd2 = [ $gRpnd2 , golemb_gRpnd3 ] { }; +void() golemb_gRpnd3 = [ $gRpnd3 , golemb_gRpnd4 ] { }; +void() golemb_gRpnd4 = [ $gRpnd4 , golemb_gRpnd5 ] { }; +void() golemb_gRpnd5 = [ $gRpnd5 , golemb_gRpnd6 ] { }; +void() golemb_gRpnd6 = [ $gRpnd6 , golemb_gRpnd7 ] { }; +void() golemb_gRpnd7 = [ $gRpnd7 , golemb_gRpnd8 ] { }; +void() golemb_gRpnd8 = [ $gRpnd8 , golemb_gRpnd9 ] { }; +void() golemb_gRpnd9 = [ $gRpnd9 , golemb_gRpnd10 ] { }; +void() golemb_gRpnd10 = [ $gRpnd10 , golemb_gRpnd11 ] { }; +void() golemb_gRpnd11 = [ $gRpnd11 , golemb_gRpnd12 ] { }; +void() golemb_gRpnd12 = [ $gRpnd12 , golemb_gRpnd13 ] { }; +void() golemb_gRpnd13 = [ $gRpnd13 , golemb_gRpnd14 ] { }; +void() golemb_gRpnd14 = [ $gRpnd14 , golemb_gRpnd15 ] { }; +void() golemb_gRpnd15 = [ $gRpnd15 , golemb_gRpnd16 ] { }; +void() golemb_gRpnd16 = [ $gRpnd16 , golemb_gRpnd17 ] { }; +void() golemb_gRpnd17 = [ $gRpnd17 , golemb_gRpnd18 ] { }; +void() golemb_gRpnd18 = [ $gRpnd18 , golemb_gRpnd19 ] { }; +void() golemb_gRpnd19 = [ $gRpnd19 , golemb_gRpnd20 ] { }; +void() golemb_gRpnd20 = [ $gRpnd20 , golem_run_init ] { }; +*/ + +/* +void() golemb_gstomp1 = [ $gstomp1 , golemb_gstomp2 ] { }; +void() golemb_gstomp2 = [ $gstomp2 , golemb_gstomp3 ] { }; +void() golemb_gstomp3 = [ $gstomp3 , golemb_gstomp4 ] { }; +void() golemb_gstomp4 = [ $gstomp4 , golemb_gstomp5 ] { }; +void() golemb_gstomp5 = [ $gstomp5 , golemb_gstomp6 ] { }; +void() golemb_gstomp6 = [ $gstomp6 , golemb_gstomp7 ] { }; +void() golemb_gstomp7 = [ $gstomp7 , golemb_gstomp8 ] { }; +void() golemb_gstomp8 = [ $gstomp8 , golemb_gstomp9 ] { }; +void() golemb_gstomp9 = [ $gstomp9 , golemb_gstomp10 ] { }; +void() golemb_gstomp10 = [ $gstomp10 , golemb_gstomp11 ] { }; +void() golemb_gstomp11 = [ $gstomp11 , golemb_gstomp12 ] { }; +void() golemb_gstomp12 = [ $gstomp12 , golemb_gstomp13 ] { }; +void() golemb_gstomp13 = [ $gstomp13 , golemb_gstomp14 ] { }; +void() golemb_gstomp14 = [ $gstomp14 , golemb_gstomp15 ] { }; +void() golemb_gstomp15 = [ $gstomp15 , golemb_gstomp16 ] { }; +void() golemb_gstomp16 = [ $gstomp16 , golemb_gstomp17 ] { }; +void() golemb_gstomp17 = [ $gstomp17 , golemb_gstomp18 ] { }; +void() golemb_gstomp18 = [ $gstomp18 , golemb_gstomp19 ] { }; +void() golemb_gstomp19 = [ $gstomp19 , golemb_gstomp20 ] { }; +void() golemb_gstomp20 = [ $gstomp20 , golemb_gstomp21 ] { }; +void() golemb_gstomp21 = [ $gstomp21 , golemb_gstomp22 ] { }; +void() golemb_gstomp22 = [ $gstomp22 , golemb_gstomp23 ] { }; +void() golemb_gstomp23 = [ $gstomp23 , golemb_gstomp24 ] { }; +void() golemb_gstomp24 = [ $gstomp24 , golemb_gstomp25 ] { }; +void() golemb_gstomp25 = [ $gstomp25 , golemb_gstomp26 ] { }; +void() golemb_gstomp26 = [ $gstomp26 , golemb_gstomp27 ] { }; +void() golemb_gstomp27 = [ $gstomp27 , golemb_gstomp28 ] { }; +void() golemb_gstomp28 = [ $gstomp28 , golemb_gstomp29 ] { }; +void() golemb_gstomp29 = [ $gstomp29 , golemb_gstomp30 ] { }; +void() golemb_gstomp30 = [ $gstomp30 , golemb_gstomp1 ] { }; +*/ + +/* +void() golemb_gtran1 = [ $gtran1 , golemb_gtran2 ] { }; +void() golemb_gtran2 = [ $gtran2 , golemb_gtran3 ] { }; +void() golemb_gtran3 = [ $gtran3 , golemb_gtran4 ] { }; +void() golemb_gtran4 = [ $gtran4 , golemb_gtran5 ] { }; +void() golemb_gtran5 = [ $gtran5 , golemb_gtran6 ] { }; +void() golemb_gtran6 = [ $gtran6 , golemb_gtran7 ] { }; +void() golemb_gtran7 = [ $gtran7 , golemb_gtran8 ] { }; +void() golemb_gtran8 = [ $gtran8 , golemb_gtran9 ] { }; +void() golemb_gtran9 = [ $gtran9 , golemb_gtran10 ] { }; +void() golemb_gtran10 = [ $gtran10 , golemb_gtran11 ] { }; +void() golemb_gtran11 = [ $gtran11 , golemb_gtran12 ] { }; +void() golemb_gtran12 = [ $gtran12 , golemb_gtran13 ] { }; +void() golemb_gtran13 = [ $gtran13 , golemb_gtran14 ] { }; +void() golemb_gtran14 = [ $gtran14 , golemb_gtran15 ] { }; +void() golemb_gtran15 = [ $gtran15 , golemb_gtran16 ] { }; +void() golemb_gtran16 = [ $gtran16 , golemb_gtran17 ] { }; +void() golemb_gtran17 = [ $gtran17 , golemb_gtran18 ] { }; +void() golemb_gtran18 = [ $gtran18 , golemb_gtran19 ] { }; +void() golemb_gtran19 = [ $gtran19 , golemb_gtran20 ] { }; +void() golemb_gtran20 = [ $gtran20 , golemb_gtran21 ] { }; +void() golemb_gtran21 = [ $gtran21 , golemb_gtran22 ] { }; +void() golemb_gtran22 = [ $gtran22 , golemb_gtran23 ] { }; +void() golemb_gtran23 = [ $gtran23 , golemb_gtran24 ] { }; +void() golemb_gtran24 = [ $gtran24 , golemb_gtran25 ] { }; +void() golemb_gtran25 = [ $gtran25 , golemb_gtran26 ] { }; +void() golemb_gtran26 = [ $gtran26 , golemb_gtran1 ] { }; +*/ + +void() golemb_gstand1 = [ $gbirth1, golemb_gstand1 ] { ai_stand(); }; + +//========================================================================== +// +// GolemBMeleeDecide +// +//========================================================================== + +void GolemBMeleeDecide(void) +{ + if(random() > 0.5) + { + GolemBPunchLeft(); + } + else + { + GolemBPoundRight(); + } +} + +//========================================================================== +// +// GolemBPunchLeft +// +//========================================================================== + +void GolemBPunchLeft(void) [++ $glpnch1..$glpnch22] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $glpnch8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $glpnch9 && self.frame < $glpnch18) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// GolemBPoundRight +// +//========================================================================== + +void GolemBPoundRight(void) [++ $grpnd1..$grpnd20] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $grpnd8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $grpnd11 && self.frame < $grpnd17) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// golemb_pain +// +//========================================================================== + +void golemb_pain(void) +{ + if(self.pain_finished > time) + { + return; + } + if(golem_flinch($gwalk1, $gwalk60)) return; + if(golem_flinch($ggem1, $ggem25)) return; + if(golem_flinch($gLpnch1, $gLpnch22)) return; + if(golem_flinch($gRpnd1, $gRpnd20)) return; + golem_flinch($gstomp1, $gstomp30); +} + +//========================================================================== +// +// monster_golem_bronze +// +//========================================================================== +/*QUAKED monster_golem_bronze (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH +Bronze Golem. +------- key / value ---------------------------- +health = 500 +experience_value = 275 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_golem_bronze(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + precache_model2("models/golem_b.mdl"); +// precache_model2("models/h_golem.mdl"); // empty for now + + precache_sound2("golem/step.wav"); + precache_sound2("golem/swing.wav"); + precache_sound2("golem/mtlfall.wav"); + precache_sound2("golem/stomp.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.thingtype = THINGTYPE_METAL; + self.yaw_speed = 10; + self.mass = 50; + self.mintel = 2; + + setmodel(self, "models/golem_b.mdl"); + + setsize(self, '-20 -20 0', '20 20 80'); + + self.health = 500; + self.experience_value = 275; + + self.th_stand = golemb_gstand1; + self.th_walk = golem_walk; + self.th_run = golem_run_init; + self.th_die = golem_die_init; + self.th_melee = GolemBMeleeDecide; + self.th_pain = golemb_pain; + self.view_ofs = '0 0 64'; + + walkmonster_start(); +} diff --git a/golem_i.hc b/golem_i.hc new file mode 100644 index 0000000..15b9615 --- /dev/null +++ b/golem_i.hc @@ -0,0 +1,396 @@ + +//************************************************************************** +//** +//** golem_i.hc +//** +//** $Header: /HexenWorld/Siege/golem_i.hc 3 5/25/98 1:38p Mgummelt $ +//** +//** Iron golem. +//** +//************************************************************************** + +// FRAMES ------------------------------------------------------------------ + +// Transition from still to attack stance +$frame gbirth1 gbirth2 gbirth3 gbirth4 gbirth5 +$frame gbirth6 gbirth7 gbirth8 gbirth9 gbirth10 +$frame gbirth11 gbirth12 + +// Death +$frame gdeath1 gdeath2 gdeath3 gdeath4 gdeath5 +$frame gdeath6 gdeath7 gdeath8 gdeath9 gdeath10 +$frame gdeath11 gdeath12 gdeath13 gdeath14 gdeath15 +$frame gdeath16 gdeath17 gdeath18 gdeath19 gdeath20 +$frame gdeath21 gdeath22 gdeath23 gdeath24 gdeath25 +$frame gdeath26 gdeath27 gdeath28 gdeath29 gdeath30 +$frame gdeath31 gdeath32 gdeath33 gdeath34 gdeath35 +$frame gdeath36 gdeath37 gdeath38 gdeath39 gdeath40 +$frame gdeath41 gdeath42 gdeath43 gdeath44 gdeath45 +$frame gdeath46 gdeath47 gdeath48 gdeath49 gdeath50 +$frame gdeath51 + +// Walking +$frame gwalk1 gwalk2 gwalk3 gwalk4 gwalk5 +$frame gwalk6 gwalk7 gwalk8 gwalk9 gwalk10 +$frame gwalk11 gwalk12 gwalk13 gwalk14 gwalk15 +$frame gwalk16 gwalk17 gwalk18 gwalk19 gwalk20 +$frame gwalk21 gwalk22 gwalk23 gwalk24 gwalk25 +$frame gwalk26 gwalk27 gwalk28 gwalk29 gwalk30 +$frame gwalk31 gwalk32 gwalk33 gwalk34 gwalk35 +$frame gwalk36 gwalk37 gwalk38 gwalk39 gwalk40 +$frame gwalk41 gwalk42 gwalk43 gwalk44 gwalk45 +$frame gwalk46 gwalk47 gwalk48 gwalk49 gwalk50 +$frame gwalk51 gwalk52 gwalk53 gwalk54 gwalk55 +$frame gwalk56 gwalk57 gwalk58 gwalk59 gwalk60 + +// Transition from attack stance to walking +$frame gtran1 gtran2 gtran3 gtran4 gtran5 +$frame gtran6 gtran7 gtran8 gtran9 gtran10 +$frame gtran11 gtran12 gtran13 gtran14 gtran15 +$frame gtran16 gtran17 gtran18 gtran19 gtran20 +$frame gtran21 gtran22 gtran23 gtran24 gtran25 +$frame gtran26 + +// Gem attack +$frame ggem1 ggem2 ggem3 ggem4 ggem5 +$frame ggem6 ggem7 ggem8 ggem9 ggem10 +$frame ggem11 ggem12 ggem13 ggem14 ggem15 +$frame ggem16 ggem17 ggem18 ggem19 ggem20 +$frame ggem21 ggem22 ggem23 ggem24 ggem25 + +// Left hand pound attack +$frame gLpnd1 gLpnd2 gLpnd3 gLpnd4 gLpnd5 +$frame gLpnd6 gLpnd7 gLpnd8 gLpnd9 gLpnd10 +$frame gLpnd11 gLpnd12 gLpnd13 gLpnd14 gLpnd15 +$frame gLpnd16 gLpnd17 gLpnd18 gLpnd19 gLpnd20 + +// Right hand punch attack +$frame gRpnch1 gRpnch2 gRpnch3 gRpnch4 gRpnch5 +$frame gRpnch6 gRpnch7 gRpnch8 gRpnch9 gRpnch10 +$frame gRpnch11 gRpnch12 gRpnch13 gRpnch14 gRpnch15 +$frame gRpnch16 gRpnch17 gRpnch18 gRpnch19 gRpnch20 +$frame gRpnch21 gRpnch22 + +void GolemIMeleeDecide(void); +void GolemIPunchRight(void); +void GolemIPoundLeft(void); + +// CODE -------------------------------------------------------------------- + +void() golemi_gbirth1 = [ $gbirth1 , golemi_gbirth2 ] { }; +void() golemi_gbirth2 = [ $gbirth2 , golemi_gbirth3 ] { }; +void() golemi_gbirth3 = [ $gbirth3 , golemi_gbirth4 ] { }; +void() golemi_gbirth4 = [ $gbirth4 , golemi_gbirth5 ] { }; +void() golemi_gbirth5 = [ $gbirth5 , golemi_gbirth6 ] { }; +void() golemi_gbirth6 = [ $gbirth6 , golemi_gbirth7 ] { }; +void() golemi_gbirth7 = [ $gbirth7 , golemi_gbirth8 ] { }; +void() golemi_gbirth8 = [ $gbirth8 , golemi_gbirth9 ] { }; +void() golemi_gbirth9 = [ $gbirth9 , golemi_gbirth10 ] { }; +void() golemi_gbirth10 = [ $gbirth10 , golemi_gbirth11 ] { }; +void() golemi_gbirth11 = [ $gbirth11 , golemi_gbirth12 ] { }; +void() golemi_gbirth12 = [ $gbirth12 , golemi_gbirth1 ] { }; + +/* +void() golemi_gdeath1 = [ $gdeath1 , golemi_gdeath2 ] { }; +void() golemi_gdeath2 = [ $gdeath2 , golemi_gdeath3 ] { }; +void() golemi_gdeath3 = [ $gdeath3 , golemi_gdeath4 ] { }; +void() golemi_gdeath4 = [ $gdeath4 , golemi_gdeath5 ] { }; +void() golemi_gdeath5 = [ $gdeath5 , golemi_gdeath6 ] { }; +void() golemi_gdeath6 = [ $gdeath6 , golemi_gdeath7 ] { }; +void() golemi_gdeath7 = [ $gdeath7 , golemi_gdeath8 ] { }; +void() golemi_gdeath8 = [ $gdeath8 , golemi_gdeath9 ] { }; +void() golemi_gdeath9 = [ $gdeath9 , golemi_gdeath10 ] { }; +void() golemi_gdeath10 = [ $gdeath10 , golemi_gdeath11 ] { }; +void() golemi_gdeath11 = [ $gdeath11 , golemi_gdeath12 ] { }; +void() golemi_gdeath12 = [ $gdeath12 , golemi_gdeath13 ] { }; +void() golemi_gdeath13 = [ $gdeath13 , golemi_gdeath14 ] { }; +void() golemi_gdeath14 = [ $gdeath14 , golemi_gdeath15 ] { }; +void() golemi_gdeath15 = [ $gdeath15 , golemi_gdeath16 ] { }; +void() golemi_gdeath16 = [ $gdeath16 , golemi_gdeath17 ] { }; +void() golemi_gdeath17 = [ $gdeath17 , golemi_gdeath18 ] { }; +void() golemi_gdeath18 = [ $gdeath18 , golemi_gdeath19 ] { }; +void() golemi_gdeath19 = [ $gdeath19 , golemi_gdeath20 ] { }; +void() golemi_gdeath20 = [ $gdeath20 , golemi_gdeath21 ] { }; +void() golemi_gdeath21 = [ $gdeath21 , golemi_gdeath22 ] { }; +void() golemi_gdeath22 = [ $gdeath22 , golemi_gdeath23 ] { }; +void() golemi_gdeath23 = [ $gdeath23 , golemi_gdeath24 ] { }; +void() golemi_gdeath24 = [ $gdeath24 , golemi_gdeath25 ] { }; +void() golemi_gdeath25 = [ $gdeath25 , golemi_gdeath26 ] { }; +void() golemi_gdeath26 = [ $gdeath26 , golemi_gdeath27 ] { }; +void() golemi_gdeath27 = [ $gdeath27 , golemi_gdeath28 ] { }; +void() golemi_gdeath28 = [ $gdeath28 , golemi_gdeath29 ] { }; +void() golemi_gdeath29 = [ $gdeath29 , golemi_gdeath30 ] { }; +void() golemi_gdeath30 = [ $gdeath30 , golemi_gdeath31 ] { }; +void() golemi_gdeath31 = [ $gdeath31 , golemi_gdeath32 ] { }; +void() golemi_gdeath32 = [ $gdeath32 , golemi_gdeath33 ] { }; +void() golemi_gdeath33 = [ $gdeath33 , golemi_gdeath34 ] { }; +void() golemi_gdeath34 = [ $gdeath34 , golemi_gdeath35 ] { }; +void() golemi_gdeath35 = [ $gdeath35 , golemi_gdeath36 ] { }; +void() golemi_gdeath36 = [ $gdeath36 , golemi_gdeath37 ] +{ + self.solid = SOLID_NOT; +}; +void() golemi_gdeath37 = [ $gdeath37 , golemi_gdeath38 ] { }; +void() golemi_gdeath38 = [ $gdeath38 , golemi_gdeath39 ] { }; +void() golemi_gdeath39 = [ $gdeath39 , golemi_gdeath40 ] { }; +void() golemi_gdeath40 = [ $gdeath40 , golemi_gdeath41 ] { }; +void() golemi_gdeath41 = [ $gdeath41 , golemi_gdeath42 ] { }; +void() golemi_gdeath42 = [ $gdeath42 , golemi_gdeath43 ] { }; +void() golemi_gdeath43 = [ $gdeath43 , golemi_gdeath44 ] { }; +void() golemi_gdeath44 = [ $gdeath44 , golemi_gdeath45 ] { }; +void() golemi_gdeath45 = [ $gdeath45 , golemi_gdeath46 ] { }; +void() golemi_gdeath46 = [ $gdeath46 , golemi_gdeath47 ] { }; +void() golemi_gdeath47 = [ $gdeath47 , golemi_gdeath48 ] { }; +void() golemi_gdeath48 = [ $gdeath48 , golemi_gdeath49 ] { }; +void() golemi_gdeath49 = [ $gdeath49 , golemi_gdeath50 ] { }; +void() golemi_gdeath50 = [ $gdeath50 , golemi_gdeath51 ] { }; +void() golemi_gdeath51 = [ $gdeath51 , golemi_gdeath51 ] { }; +*/ + +/* +void() golemi_ggem1 = [ $ggem1 , golemi_ggem2 ] {ai_face(); }; +void() golemi_ggem2 = [ $ggem2 , golemi_ggem3 ] {ai_face(); }; +void() golemi_ggem3 = [ $ggem3 , golemi_ggem4 ] {ai_face(); }; +void() golemi_ggem4 = [ $ggem4 , golemi_ggem5 ] {ai_face(); }; +void() golemi_ggem5 = [ $ggem5 , golemi_ggem6 ] {ai_face(); }; +void() golemi_ggem6 = [ $ggem6 , golemi_ggem7 ] {ai_face(); }; +void() golemi_ggem7 = [ $ggem7 , golemi_ggem8 ] {ai_face(); }; +void() golemi_ggem8 = [ $ggem8 , golemi_ggem9 ] {ai_face(); }; +void() golemi_ggem9 = [ $ggem9 , golemi_ggem10 ] {ai_face(); }; +void() golemi_ggem10 = [ $ggem10 , golemi_ggem11 ] {ai_face(); }; +void() golemi_ggem11 = [ $ggem11 , golemi_ggem12 ] {ai_face(); }; +void() golemi_ggem12 = [ $ggem12 , golemi_ggem13 ] {ai_face(); }; +void() golemi_ggem13 = [ $ggem13 , golemi_ggem14 ] {ai_face();}; +void() golemi_ggem14 = [ $ggem14 , golemi_ggem15 ] {ai_face(); }; +void() golemi_ggem15 = [ $ggem15 , golemi_ggem16 ] {ai_face(); }; +void() golemi_ggem16 = [ $ggem16 , golemi_ggem17 ] {ai_face(); }; +void() golemi_ggem17 = [ $ggem17 , golemi_ggem18 ] {ai_face();}; +void() golemi_ggem18 = [ $ggem18 , golemi_ggem19 ] {ai_face(); }; +void() golemi_ggem19 = [ $ggem19 , golemi_ggem20 ] {ai_face(); }; +void() golemi_ggem20 = [ $ggem20 , golemi_ggem21 ] {ai_face(); }; +void() golemi_ggem21 = [ $ggem21 , golemi_ggem22 ] {ai_face();}; +void() golemi_ggem22 = [ $ggem22 , golemi_ggem23 ] {ai_face(); }; +void() golemi_ggem23 = [ $ggem23 , golemi_ggem24 ] {ai_face(); }; +void() golemi_ggem24 = [ $ggem24 , golemi_ggem25 ] {ai_face(); }; +void() golemi_ggem25 = [ $ggem25 , golem_run_init ] {ai_face(); }; +*/ + +/* +void() golemi_gLpnd1 = [ $gLpnd1 , golemi_gLpnd2 ] { }; +void() golemi_gLpnd2 = [ $gLpnd2 , golemi_gLpnd3 ] { }; +void() golemi_gLpnd3 = [ $gLpnd3 , golemi_gLpnd4 ] { }; +void() golemi_gLpnd4 = [ $gLpnd4 , golemi_gLpnd5 ] { }; +void() golemi_gLpnd5 = [ $gLpnd5 , golemi_gLpnd6 ] { }; +void() golemi_gLpnd6 = [ $gLpnd6 , golemi_gLpnd7 ] { }; +void() golemi_gLpnd7 = [ $gLpnd7 , golemi_gLpnd8 ] { }; +void() golemi_gLpnd8 = [ $gLpnd8 , golemi_gLpnd9 ] { }; +void() golemi_gLpnd9 = [ $gLpnd9 , golemi_gLpnd10 ] { }; +void() golemi_gLpnd10 = [ $gLpnd10 , golemi_gLpnd11 ] { }; +void() golemi_gLpnd11 = [ $gLpnd11 , golemi_gLpnd12 ] { }; +void() golemi_gLpnd12 = [ $gLpnd12 , golemi_gLpnd13 ] { }; +void() golemi_gLpnd13 = [ $gLpnd13 , golemi_gLpnd14 ] { }; +void() golemi_gLpnd14 = [ $gLpnd14 , golemi_gLpnd15 ] { }; +void() golemi_gLpnd15 = [ $gLpnd15 , golemi_gLpnd16 ] { }; +void() golemi_gLpnd16 = [ $gLpnd16 , golemi_gLpnd17 ] { }; +void() golemi_gLpnd17 = [ $gLpnd17 , golemi_gLpnd18 ] { }; +void() golemi_gLpnd18 = [ $gLpnd18 , golemi_gLpnd19 ] { }; +void() golemi_gLpnd19 = [ $gLpnd19 , golemi_gLpnd20 ] { }; +void() golemi_gLpnd20 = [ $gLpnd20 , golem_run_init ] { }; +*/ + +/* +void() golemi_gRpnch1 = [ $gRpnch1 , golemi_gRpnch2 ] { }; +void() golemi_gRpnch2 = [ $gRpnch2 , golemi_gRpnch3 ] { }; +void() golemi_gRpnch3 = [ $gRpnch3 , golemi_gRpnch4 ] { }; +void() golemi_gRpnch4 = [ $gRpnch4 , golemi_gRpnch5 ] { }; +void() golemi_gRpnch5 = [ $gRpnch5 , golemi_gRpnch6 ] { }; +void() golemi_gRpnch6 = [ $gRpnch6 , golemi_gRpnch7 ] { }; +void() golemi_gRpnch7 = [ $gRpnch7 , golemi_gRpnch8 ] { }; +void() golemi_gRpnch8 = [ $gRpnch8 , golemi_gRpnch9 ] { }; +void() golemi_gRpnch9 = [ $gRpnch9 , golemi_gRpnch10 ] { }; +void() golemi_gRpnch10 = [ $gRpnch10 , golemi_gRpnch11 ] { }; +void() golemi_gRpnch11 = [ $gRpnch11 , golemi_gRpnch12 ] { }; +void() golemi_gRpnch12 = [ $gRpnch12 , golemi_gRpnch13 ] { }; +void() golemi_gRpnch13 = [ $gRpnch13 , golemi_gRpnch14 ] { }; +void() golemi_gRpnch14 = [ $gRpnch14 , golemi_gRpnch15 ] { }; +void() golemi_gRpnch15 = [ $gRpnch15 , golemi_gRpnch16 ] { }; +void() golemi_gRpnch16 = [ $gRpnch16 , golemi_gRpnch17 ] { }; +void() golemi_gRpnch17 = [ $gRpnch17 , golemi_gRpnch18 ] { }; +void() golemi_gRpnch18 = [ $gRpnch18 , golemi_gRpnch19 ] { }; +void() golemi_gRpnch19 = [ $gRpnch19 , golemi_gRpnch20 ] { }; +void() golemi_gRpnch20 = [ $gRpnch20 , golemi_gRpnch21 ] { }; +void() golemi_gRpnch21 = [ $gRpnch21 , golemi_gRpnch22 ] { }; +void() golemi_gRpnch22 = [ $gRpnch22 , golem_run_init ] { }; +*/ + +/* +void() golemi_gtran1 = [ $gtran1 , golemi_gtran2 ] { }; +void() golemi_gtran2 = [ $gtran2 , golemi_gtran3 ] { }; +void() golemi_gtran3 = [ $gtran3 , golemi_gtran4 ] { }; +void() golemi_gtran4 = [ $gtran4 , golemi_gtran5 ] { }; +void() golemi_gtran5 = [ $gtran5 , golemi_gtran6 ] { }; +void() golemi_gtran6 = [ $gtran6 , golemi_gtran7 ] { }; +void() golemi_gtran7 = [ $gtran7 , golemi_gtran8 ] { }; +void() golemi_gtran8 = [ $gtran8 , golemi_gtran9 ] { }; +void() golemi_gtran9 = [ $gtran9 , golemi_gtran10 ] { }; +void() golemi_gtran10 = [ $gtran10 , golemi_gtran11 ] { }; +void() golemi_gtran11 = [ $gtran11 , golemi_gtran12 ] { }; +void() golemi_gtran12 = [ $gtran12 , golemi_gtran13 ] { }; +void() golemi_gtran13 = [ $gtran13 , golemi_gtran14 ] { }; +void() golemi_gtran14 = [ $gtran14 , golemi_gtran15 ] { }; +void() golemi_gtran15 = [ $gtran15 , golemi_gtran16 ] { }; +void() golemi_gtran16 = [ $gtran16 , golemi_gtran17 ] { }; +void() golemi_gtran17 = [ $gtran17 , golemi_gtran18 ] { }; +void() golemi_gtran18 = [ $gtran18 , golemi_gtran19 ] { }; +void() golemi_gtran19 = [ $gtran19 , golemi_gtran20 ] { }; +void() golemi_gtran20 = [ $gtran20 , golemi_gtran21 ] { }; +void() golemi_gtran21 = [ $gtran21 , golemi_gtran22 ] { }; +void() golemi_gtran22 = [ $gtran22 , golemi_gtran23 ] { }; +void() golemi_gtran23 = [ $gtran23 , golemi_gtran24 ] { }; +void() golemi_gtran24 = [ $gtran24 , golemi_gtran25 ] { }; +void() golemi_gtran25 = [ $gtran25 , golemi_gtran26 ] { }; +void() golemi_gtran26 = [ $gtran26 , golemi_gtran1 ] { }; +*/ + +void() golemi_gstand1 = [ $gbirth1, golemi_gstand1 ] { ai_stand(); }; + +//========================================================================== +// +// GolemIMeleeDecide +// +//========================================================================== + +void GolemIMeleeDecide(void) +{ + if(random() > 0.5) + { + GolemIPunchRight(); + } + else + { + GolemIPoundLeft(); + } +} + +//========================================================================== +// +// GolemIPunchRight +// +//========================================================================== + +void GolemIPunchRight(void) [++ $grpnch1..$grpnch22] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $grpnch8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $grpnch9 && self.frame < $grpnch18) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// GolemIPoundLeft +// +//========================================================================== + +void GolemIPoundLeft(void) [++ $glpnd1..$glpnd20] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $glpnd8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $glpnd11 && self.frame < $glpnd17) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// golemi_pain +// +//========================================================================== + +void golemi_pain(void) +{ + if(self.pain_finished > time) + { + return; + } + if(golem_flinch($gwalk1, $gwalk60)) return; + if(golem_flinch($ggem1, $ggem25)) return; + if(golem_flinch($gRpnch1, $gRpnch22)) return; + golem_flinch($gLpnd1, $gLpnd20); +} + +//========================================================================== +// +// monster_golem_iron +// +//========================================================================== +/*QUAKED monster_golem_iron (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH +Iron Golem. +------- key / value ---------------------------- +health = 400 +experience_value = 200 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_golem_iron(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + precache_model2("models/golem_i.mdl"); +// precache_model2("models/h_golem.mdl"); // empty for now + + precache_sound2("golem/step.wav"); + precache_sound2("golem/swing.wav"); + precache_sound2("golem/mtlfall.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.thingtype = THINGTYPE_METAL; + self.yaw_speed = 10; + self.mass = 100; + self.mintel = 2; + + setmodel(self, "models/golem_i.mdl"); + + setsize(self, '-20 -20 0', '20 20 80'); + + self.health = 400; + self.experience_value = 200; + + self.th_stand = golemi_gstand1; + self.th_walk = golem_walk; + self.th_run = golem_run_init; + self.th_die = golem_die_init; + self.th_melee = GolemIMeleeDecide; + //self.th_missile = golemi_ggem1; + self.th_pain = golemi_pain; + self.view_ofs = '0 0 64'; + + walkmonster_start(); +} diff --git a/golem_s.hc b/golem_s.hc new file mode 100644 index 0000000..6359a72 --- /dev/null +++ b/golem_s.hc @@ -0,0 +1,557 @@ + +//************************************************************************** +//** +//** golem_s.hc +//** +//** $Header: /HexenWorld/Siege/golem_s.hc 3 5/25/98 1:38p Mgummelt $ +//** +//** Stone golem. Also contains generic golem code. +//** +//************************************************************************** + +// FRAMES ------------------------------------------------------------------ + +// Transition from still to attack stance +$frame gbirth1 gbirth2 gbirth3 gbirth4 gbirth5 +$frame gbirth6 gbirth7 gbirth8 gbirth9 gbirth10 +$frame gbirth11 gbirth12 + +// Death +$frame gdeath1 gdeath2 gdeath3 gdeath4 gdeath5 +$frame gdeath6 gdeath7 gdeath8 gdeath9 gdeath10 +$frame gdeath11 gdeath12 gdeath13 gdeath14 gdeath15 +$frame gdeath16 gdeath17 gdeath18 gdeath19 gdeath20 +$frame gdeath21 gdeath22 gdeath23 gdeath24 gdeath25 +$frame gdeath26 gdeath27 gdeath28 gdeath29 gdeath30 +$frame gdeath31 gdeath32 gdeath33 gdeath34 gdeath35 +$frame gdeath36 gdeath37 gdeath38 gdeath39 gdeath40 +$frame gdeath41 gdeath42 gdeath43 gdeath44 gdeath45 +$frame gdeath46 gdeath47 gdeath48 gdeath49 gdeath50 +$frame gdeath51 + +// Walking +$frame gwalk1 gwalk2 gwalk3 gwalk4 gwalk5 +$frame gwalk6 gwalk7 gwalk8 gwalk9 gwalk10 +$frame gwalk11 gwalk12 gwalk13 gwalk14 gwalk15 +$frame gwalk16 gwalk17 gwalk18 gwalk19 gwalk20 +$frame gwalk21 gwalk22 gwalk23 gwalk24 gwalk25 +$frame gwalk26 gwalk27 gwalk28 gwalk29 gwalk30 +$frame gwalk31 gwalk32 gwalk33 gwalk34 gwalk35 +$frame gwalk36 gwalk37 gwalk38 gwalk39 gwalk40 +$frame gwalk41 gwalk42 gwalk43 gwalk44 gwalk45 +$frame gwalk46 gwalk47 gwalk48 gwalk49 gwalk50 +$frame gwalk51 gwalk52 gwalk53 gwalk54 gwalk55 +$frame gwalk56 gwalk57 gwalk58 gwalk59 gwalk60 + +// Transition from attack stance to walking +$frame gtran1 gtran2 gtran3 gtran4 gtran5 +$frame gtran6 gtran7 gtran8 gtran9 gtran10 +$frame gtran11 gtran12 gtran13 gtran14 gtran15 +$frame gtran16 gtran17 gtran18 gtran19 gtran20 +$frame gtran21 gtran22 gtran23 gtran24 gtran25 +$frame gtran26 + +// Two hand pound attack +$frame gDpnd1 gDpnd2 gDpnd3 gDpnd4 gDpnd5 +$frame gDpnd6 gDpnd7 gDpnd8 gDpnd9 gDpnd10 +$frame gDpnd11 gDpnd12 gDpnd13 gDpnd14 gDpnd15 +$frame gDpnd16 gDpnd17 gDpnd18 gDpnd19 gDpnd20 + +// Left hand punch attack +$frame gLpnch1 gLpnch2 gLpnch3 gLpnch4 gLpnch5 +$frame gLpnch6 gLpnch7 gLpnch8 gLpnch9 gLpnch10 +$frame gLpnch11 gLpnch12 gLpnch13 gLpnch14 gLpnch15 +$frame gLpnch16 gLpnch17 gLpnch18 gLpnch19 gLpnch20 +$frame gLpnch21 gLpnch22 + +// Right hand punch attack +$frame gRpnch1 gRpnch2 gRpnch3 gRpnch4 gRpnch5 +$frame gRpnch6 gRpnch7 gRpnch8 gRpnch9 gRpnch10 +$frame gRpnch11 gRpnch12 gRpnch13 gRpnch14 gRpnch15 +$frame gRpnch16 gRpnch17 gRpnch18 gRpnch19 gRpnch20 +$frame gRpnch21 gRpnch22 + +$framevalue 0 + +$frame tgrun1 tgrun2 tgrun3 tgrun4 tgrun5 +$frame tgrun6 tgrun7 tgrun8 tgrun9 tgrun10 +$frame tgrun11 tgrun12 tgrun13 tgrun14 tgrun15 +$frame tgrun16 tgrun17 tgrun18 tgrun19 tgrun20 +$frame tgrun21 tgrun22 tgrun23 tgrun24 + +$frame tgwalk1 tgwalk2 tgwalk3 tgwalk4 tgwalk5 +$frame tgwalk6 tgwalk7 tgwalk8 tgwalk9 tgwalk10 +$frame tgwalk11 tgwalk12 tgwalk13 tgwalk14 tgwalk15 +$frame tgwalk16 tgwalk17 tgwalk18 tgwalk19 tgwalk20 +$frame tgwalk21 tgwalk22 tgwalk23 tgwalk24 tgwalk25 +$frame tgwalk26 tgwalk27 tgwalk28 tgwalk29 tgwalk30 +$frame tgwalk31 tgwalk32 tgwalk33 tgwalk34 + +void GolemSPunchLeft(void); +void GolemSPunchRight(void); +void GolemSPound(void); +void golem_run_init(void); + +// CODE -------------------------------------------------------------------- + +void() golems_gbirth1 = [ $gbirth1 , golems_gbirth2 ] { }; +void() golems_gbirth2 = [ $gbirth2 , golems_gbirth3 ] { }; +void() golems_gbirth3 = [ $gbirth3 , golems_gbirth4 ] { }; +void() golems_gbirth4 = [ $gbirth4 , golems_gbirth5 ] { }; +void() golems_gbirth5 = [ $gbirth5 , golems_gbirth6 ] { }; +void() golems_gbirth6 = [ $gbirth6 , golems_gbirth7 ] { }; +void() golems_gbirth7 = [ $gbirth7 , golems_gbirth8 ] { }; +void() golems_gbirth8 = [ $gbirth8 , golems_gbirth9 ] { }; +void() golems_gbirth9 = [ $gbirth9 , golems_gbirth10 ] { }; +void() golems_gbirth10 = [ $gbirth10 , golems_gbirth11 ] { }; +void() golems_gbirth11 = [ $gbirth11 , golems_gbirth12 ] { }; +void() golems_gbirth12 = [ $gbirth12 , golems_gbirth1 ] { }; + +/* +void() golems_gDpnd1 = [ $gDpnd1 , golems_gDpnd2 ] { }; +void() golems_gDpnd2 = [ $gDpnd2 , golems_gDpnd3 ] { }; +void() golems_gDpnd3 = [ $gDpnd3 , golems_gDpnd4 ] { }; +void() golems_gDpnd4 = [ $gDpnd4 , golems_gDpnd5 ] { }; +void() golems_gDpnd5 = [ $gDpnd5 , golems_gDpnd6 ] { }; +void() golems_gDpnd6 = [ $gDpnd6 , golems_gDpnd7 ] { }; +void() golems_gDpnd7 = [ $gDpnd7 , golems_gDpnd8 ] { }; +void() golems_gDpnd8 = [ $gDpnd8 , golems_gDpnd9 ] { }; +void() golems_gDpnd9 = [ $gDpnd9 , golems_gDpnd10 ] { }; +void() golems_gDpnd10 = [ $gDpnd10 , golems_gDpnd11 ] { }; +void() golems_gDpnd11 = [ $gDpnd11 , golems_gDpnd12 ] { }; +void() golems_gDpnd12 = [ $gDpnd12 , golems_gDpnd13 ] { }; +void() golems_gDpnd13 = [ $gDpnd13 , golems_gDpnd14 ] { }; +void() golems_gDpnd14 = [ $gDpnd14 , golems_gDpnd15 ] { }; +void() golems_gDpnd15 = [ $gDpnd15 , golems_gDpnd16 ] { }; +void() golems_gDpnd16 = [ $gDpnd16 , golems_gDpnd17 ] { }; +void() golems_gDpnd17 = [ $gDpnd17 , golems_gDpnd18 ] { }; +void() golems_gDpnd18 = [ $gDpnd18 , golems_gDpnd19 ] { }; +void() golems_gDpnd19 = [ $gDpnd19 , golems_gDpnd20 ] { }; +void() golems_gDpnd20 = [ $gDpnd20 , golem_run_init ] { }; + +void() golems_gLpnch1 = [ $gLpnch1 , golems_gLpnch2 ] { }; +void() golems_gLpnch2 = [ $gLpnch2 , golems_gLpnch3 ] { }; +void() golems_gLpnch3 = [ $gLpnch3 , golems_gLpnch4 ] { }; +void() golems_gLpnch4 = [ $gLpnch4 , golems_gLpnch5 ] { }; +void() golems_gLpnch5 = [ $gLpnch5 , golems_gLpnch6 ] { }; +void() golems_gLpnch6 = [ $gLpnch6 , golems_gLpnch7 ] { }; +void() golems_gLpnch7 = [ $gLpnch7 , golems_gLpnch8 ] { }; +void() golems_gLpnch8 = [ $gLpnch8 , golems_gLpnch9 ] { }; +void() golems_gLpnch9 = [ $gLpnch9 , golems_gLpnch10 ] { }; +void() golems_gLpnch10 = [ $gLpnch10 , golems_gLpnch11 ] { }; +void() golems_gLpnch11 = [ $gLpnch11 , golems_gLpnch12 ] { }; +void() golems_gLpnch12 = [ $gLpnch12 , golems_gLpnch13 ] { }; +void() golems_gLpnch13 = [ $gLpnch13 , golems_gLpnch14 ] { }; +void() golems_gLpnch14 = [ $gLpnch14 , golems_gLpnch15 ] { }; +void() golems_gLpnch15 = [ $gLpnch15 , golems_gLpnch16 ] { }; +void() golems_gLpnch16 = [ $gLpnch16 , golems_gLpnch17 ] { }; +void() golems_gLpnch17 = [ $gLpnch17 , golems_gLpnch18 ] { }; +void() golems_gLpnch18 = [ $gLpnch18 , golems_gLpnch19 ] { }; +void() golems_gLpnch19 = [ $gLpnch19 , golems_gLpnch20 ] { }; +void() golems_gLpnch20 = [ $gLpnch20 , golems_gLpnch21 ] { }; +void() golems_gLpnch21 = [ $gLpnch21 , golems_gLpnch22 ] { }; +void() golems_gLpnch22 = [ $gLpnch22 , golem_run_init ] { }; + +void() + golems_gRpnch1 = [$gRpnch1 golems_gRpnch2 ], + golems_gRpnch2 = [$gRpnch2 golems_gRpnch3 ], + golems_gRpnch3 = [$gRpnch3 golems_gRpnch4 ], + golems_gRpnch4 = [$gRpnch4 golems_gRpnch5 ], + golems_gRpnch5 = [$gRpnch5 golems_gRpnch6 ], + golems_gRpnch6 = [$gRpnch6 golems_gRpnch7 ], + golems_gRpnch7 = [$gRpnch7 golems_gRpnch8 ], + golems_gRpnch8 = [$gRpnch8 golems_gRpnch9 ], + golems_gRpnch9 = [$gRpnch9 golems_gRpnch10 ], + golems_gRpnch10 = [$gRpnch10 golems_gRpnch11 ], + golems_gRpnch11 = [$gRpnch11 golems_gRpnch12 ], + golems_gRpnch12 = [$gRpnch12 golems_gRpnch13 ], + golems_gRpnch13 = [$gRpnch13 golems_gRpnch14 ], + golems_gRpnch14 = [$gRpnch14 golems_gRpnch15 ], + golems_gRpnch15 = [$gRpnch15 golems_gRpnch16 ], + golems_gRpnch16 = [$gRpnch16 golems_gRpnch17 ], + golems_gRpnch17 = [$gRpnch17 golems_gRpnch18 ], + golems_gRpnch18 = [$gRpnch18 golems_gRpnch19 ], + golems_gRpnch19 = [$gRpnch19 golems_gRpnch20 ], + golems_gRpnch20 = [$gRpnch20 golems_gRpnch21 ], + golems_gRpnch21 = [$gRpnch21 golems_gRpnch22 ], + golems_gRpnch22 = [$gRpnch22 golem_run_init ]; +*/ + +/* +void() golems_gtran1 = [ $gtran1 , golems_gtran2 ] { }; +void() golems_gtran2 = [ $gtran2 , golems_gtran3 ] { }; +void() golems_gtran3 = [ $gtran3 , golems_gtran4 ] { }; +void() golems_gtran4 = [ $gtran4 , golems_gtran5 ] { }; +void() golems_gtran5 = [ $gtran5 , golems_gtran6 ] { }; +void() golems_gtran6 = [ $gtran6 , golems_gtran7 ] { }; +void() golems_gtran7 = [ $gtran7 , golems_gtran8 ] { }; +void() golems_gtran8 = [ $gtran8 , golems_gtran9 ] { }; +void() golems_gtran9 = [ $gtran9 , golems_gtran10 ] { }; +void() golems_gtran10 = [ $gtran10 , golems_gtran11 ] { }; +void() golems_gtran11 = [ $gtran11 , golems_gtran12 ] { }; +void() golems_gtran12 = [ $gtran12 , golems_gtran13 ] { }; +void() golems_gtran13 = [ $gtran13 , golems_gtran14 ] { }; +void() golems_gtran14 = [ $gtran14 , golems_gtran15 ] { }; +void() golems_gtran15 = [ $gtran15 , golems_gtran16 ] { }; +void() golems_gtran16 = [ $gtran16 , golems_gtran17 ] { }; +void() golems_gtran17 = [ $gtran17 , golems_gtran18 ] { }; +void() golems_gtran18 = [ $gtran18 , golems_gtran19 ] { }; +void() golems_gtran19 = [ $gtran19 , golems_gtran20 ] { }; +void() golems_gtran20 = [ $gtran20 , golems_gtran21 ] { }; +void() golems_gtran21 = [ $gtran21 , golems_gtran22 ] { }; +void() golems_gtran22 = [ $gtran22 , golems_gtran23 ] { }; +void() golems_gtran23 = [ $gtran23 , golems_gtran24 ] { }; +void() golems_gtran24 = [ $gtran24 , golems_gtran25 ] { }; +void() golems_gtran25 = [ $gtran25 , golems_gtran26 ] { }; +void() golems_gtran26 = [ $gtran26 , golems_gtran1 ] { }; +*/ + +void() golems_gstand1 = [ $gbirth1, golems_gstand1 ] +{ + ai_stand(); +}; + +//========================================================================== +// +// GolemSMeleeDecide +// +//========================================================================== + +void GolemSMeleeDecide(void) +{ + float rnd; + + rnd = random(); + if(rnd > 0.66) + { + GolemSPunchLeft(); + } + else if(rnd > 0.33) + { + GolemSPunchRight(); + } + else + { + GolemSPound(); + } +} + +//========================================================================== +// +// GolemSPunchLeft +// +//========================================================================== + +void GolemSPunchLeft(void) [++ $glpnch1..$glpnch22] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $glpnch8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $glpnch9 && self.frame < $glpnch18) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// GolemSPunchRight +// +//========================================================================== + +void GolemSPunchRight(void) [++ $grpnch1..$grpnch22] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $grpnch8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $grpnch9 && self.frame < $grpnch18) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// GolemSPound +// +//========================================================================== + +void GolemSPound(void) [++ $gdpnd1..$gdpnd20] +{ + if(cycle_wrapped) + { + golem_run_init(); + return; + } + if(self.frame == $gdpnd8) + { + sound(self, CHAN_BODY, "golem/swing.wav", 1, ATTN_NORM); + } + if(self.frame > $gdpnd9 && self.frame < $gdpnd18) + { + ai_charge(2); + ai_melee(); + } + ai_face(); +} + +//========================================================================== +// +// golem_run +// +//========================================================================== + +void golem_run(void) +{ + vector tvec; + + if(self.count == 20) + { + if(self.frame == $tgrun24) + { + self.frame = $tgrun1; + } + else + { + self.frame += 1; + } + ai_run(6); + } + else + { + if(self.frame == $tgwalk34) + { + self.frame = $tgwalk1; + } + else + { + self.frame += 1; + } + ai_run(3); + } + + +// if(self.frame == $gwalk27 || self.frame == $gwalk58) +// { +// sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); +// } + + thinktime self : HX_FRAME_TIME; +} + +void golem_run_init(void) +{ + if(self.count == 20) + { + if(self.frame < $tgrun1 || self.frame > $tgrun24) + { + self.frame = $tgrun1; + } + ai_run(2); + } + else + { + if(self.frame < $tgwalk1 || self.frame > $tgwalk34) + { + self.frame = $tgwalk1; + } + ai_run(1); + } + + thinktime self : HX_FRAME_TIME; + self.think = golem_run; +} + +//========================================================================== +// +// golem_walk +// +//========================================================================== + +void golem_walk(void) [++ $gwalk1..$gwalk60] +{ + if(self.frame == $gwalk27 || self.frame == $gwalk58) + { + sound(self, CHAN_BODY, "golem/step.wav", 1, ATTN_NORM); + } + ai_walk(1); +} + +//========================================================================== +// +// golem_die +// +//========================================================================== + +void golem_die(void) +{ + if(self.frame == $gdeath51) + { + self.nextthink = time - 1; +/* if(self.classname == "monster_golem_stone") + { + } + else if(self.classname == "monster_golem_iron") + { + } + else + { // Assumed bronze + } +*/ + MakeSolidCorpse(); + return; + } + if(self.frame == $gdeath36) + { + self.solid = SOLID_NOT; + } + if(self.health<-50) + self.think=chunk_death; + if(self.flags&FL_ONGROUND) + self.frame += 1; + self.nextthink = time + HX_FRAME_TIME; +} + +void golem_die_init(void) [ $gdeath1, golem_die ] +{ +} + +//========================================================================== +// +// golem_flinch +// +//========================================================================== + +float golem_flinch(float firstFrame, float lastFrame) +{ + if(self.frame < firstFrame || self.frame > lastFrame) + { + return 0; + } + self.nextthink = self.nextthink+0.1+random()*0.2; + self.frame = self.frame - 8 - rint(random() * 12); + self.pain_finished = time + 1; + if(self.frame < firstFrame) + { // Wrap + self.frame = lastFrame + 1 - (firstFrame - self.frame); + } + return 1; +} + +//========================================================================== +// +// golems_pain +// +//========================================================================== + +void golems_pain(void) +{ + +/* float i; + + i = (self.drawflags&MLS_MASKIN)+1; + if(i > 7) + { + i = 0; + } + self.drawflags = (self.drawflags&MLS_MASKOUT)|i; + dprint("mls="); + dprint(ftos(i)); + dprint("\n"); +*/ + if(self.count == 20) + { + self.count = 0; + } + else + { + self.count = 20; + } + + + if(self.pain_finished > time) + { + return; + } + if(golem_flinch($gwalk1, $gwalk60)) return; + if(golem_flinch($gLpnch1, $gLpnch22)) return; + if(golem_flinch($gRpnch1, $gRpnch22)) return; + golem_flinch($gDpnd1, $gDpnd20); +} + +//========================================================================== +// +// monster_golem_stone +// +//========================================================================== +/*QUAKED monster_golem_stone (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH +Stone Golem. +------- key / value ---------------------------- +health = 200 +experience_value = 125 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_golem_stone(void) +{ + if(deathmatch) + { + remove(self); + return; + } + + //precache_model("models/golem_s.mdl"); + precache_model("models/goltest.mdl"); +// precache_model("models/h_golem.mdl"); // empty for now + + precache_sound2("golem/awaken.wav"); + precache_sound2("golem/step.wav"); + precache_sound2("golem/swing.wav"); + precache_sound2("golem/stnpain.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.thingtype = THINGTYPE_GREYSTONE; + self.yaw_speed = 10; + self.mass = 75; + self.mintel = 2; + + //setmodel(self, "models/golem_s.mdl"); + setmodel(self, "models/goltest.mdl"); + + //setsize(self, '-20 -20 0', '20 20 80'); + setsize(self, '-20 -20 -20', '20 20 60'); + + self.scale = 1.5; + + self.health = 200; + self.experience_value = 125; + + self.th_stand = golems_gstand1; + self.th_walk = golem_walk; + self.th_run = golem_run_init; + self.th_die = golem_die_init; + self.th_melee = GolemSMeleeDecide; + //self.th_missile = golems_run_init; + self.th_pain = golems_pain; + self.view_ofs = '0 0 64'; + + walkmonster_start(); +} diff --git a/grenade2.hc b/grenade2.hc new file mode 100644 index 0000000..def5c0d --- /dev/null +++ b/grenade2.hc @@ -0,0 +1,200 @@ +void() SmallExplosion = +{ + particle (self.origin, '0 0 10', 242, 5); + self.movetype = MOVETYPE_NONE; + self.velocity = '0 0 0'; + self.touch = SUB_Null; + self.solid = SOLID_NOT; + sound(self,CHAN_AUTO,"weapons/r_exp3.wav",0.25,ATTN_NORM); + remove(self); +}; + +void() CB_BoltStick; +void(float offset) W_FireFlame; +void()BlowUp= +{ + if(self.mass<2.5) + { + self.v_angle_x=random()*360; + self.v_angle_y=random()*360; + self.v_angle_z=random()*360; + self.scale=self.mass; +// W_FireFlame(random()*360); +// W_FireFlame(random()*360); + T_RadiusDamage (self, self.owner, self.mass*100, world); + self.mass += 0.1; + self.think=BlowUp; + self.nextthink=time;//+0.1; + } + else + { + self.think=SUB_Remove; + self.nextthink=time; + } +}; + +void() SprayFire= +{ +local entity fireballblast; + sound(self,CHAN_AUTO,"weapons/fbfire.wav",1,ATTN_NORM); + fireballblast=spawn(); + fireballblast.movetype=MOVETYPE_NOCLIP; + fireballblast.owner=self.owner; + fireballblast.classname="fireballblast"; + fireballblast.solid=SOLID_NOT; + fireballblast.drawflags +=MLS_ABSLIGHT+SCALE_TYPE_UNIFORM+SCALE_ORIGIN_CENTER; + fireballblast.abslight= 1; + fireballblast.scale=0.1; + setmodel(fireballblast,"progs/blast.mdl"); + setsize(fireballblast,'0 0 0','0 0 0'); + setorigin(fireballblast,self.origin); + fireballblast.effects=EF_BRIGHTLIGHT; + fireballblast.mass=0.1; + fireballblast.avelocity='50 50 50'; + fireballblast.think=BlowUp; + fireballblast.nextthink=time; +}; + +void() GrenadeExplode2 = +{ + if(self.classname=="stickmine") + SprayFire(); + T_RadiusDamage (self, self.owner, self.mass, world); + + if(self.small) + SmallExplosion(); + else + { + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_EXPLOSION); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + + BecomeExplosion (); + } +}; + +void() MultipleExplode; + +void() GrenadeTouch2 = +{ + if (other == self.owner) + return; // don't explode on owner + if(other.owner==self.owner&&other.classname==self.classname&&self.classname=="minigrenade") + return; + +// if (other.takedamage == DAMAGE_YES) + if (other.takedamage) + { + if(self.classname=="multigrenade") + MultipleExplode(); + else GrenadeExplode2(); + return; + } + sound (self, CHAN_WEAPON, "idweapons/tink1.wav", 1, ATTN_NORM); // bounce sound + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; +}; + +void() StickMineTouch = +{ + if(other==self.owner) + return; +local vector stickdir; + sound(self, CHAN_WEAPON, "idweapons/pkup.wav", 1, ATTN_NORM); + if(other.takedamage) + { +// makevectors(self.angles); + stickdir=other.origin+normalize(self.origin-other.origin)*12; +//Modify height for shorter or taller models like imp, golem, spider, etc. + if(other.classname=="player") +//Put it right below view of player + stickdir_z=other.origin_z+other.view_ofs_z - 5; + else if(other.classname=="monster_spider") + stickdir_z=(self.origin_z+(other.origin_z+other.size_z*0.2)*3)*0.25; + else stickdir_z=(self.origin_z+(other.origin_z+other.size_z*0.6)*3)*0.25; + setorigin(self,stickdir); + T_Damage(other,self,self.owner,3); + SpawnPuff(self.origin+v_forward*8,'0 0 0'-v_forward*24,10,other); + } + else + SpawnPuff(self.origin+v_forward*8,'0 0 0'-v_forward*24,10,world); + + self.velocity='0 0 0'; + self.movetype=MOVETYPE_NOCLIP; + self.solid=SOLID_NOT; + self.touch=SUB_Null; + self.wait=time + 2; + self.health=other.health; + if(other.movetype) + { + self.enemy=other; + self.view_ofs=(self.origin-other.origin); + self.o_angle=(self.angles-self.enemy.angles); + self.think=CB_BoltStick; + self.nextthink=time; + } + else + { + self.movetype=MOVETYPE_NONE; + self.think=GrenadeExplode2; + self.nextthink=time + 2; + } +}; + +void() Use_StickMine = +{ + self.attack_finished=time + 0.2; + makevectors(self.v_angle); +//sound + local entity missile; + missile=spawn(); + missile.owner=self; + missile.classname="stickmine"; + missile.movetype=MOVETYPE_BOUNCE; + missile.solid=SOLID_BBOX; +// missile.takedamage=DAMAGE_YES; +// missile.health=10; +// missile.th_die=GrenadeExplode2; + missile.touch=StickMineTouch; + missile.mass=50; + + missile.velocity=normalize(v_forward)*700 +v_up*200; + missile.avelocity_x=random()*600 - 300; + missile.avelocity_y=random()*600 - 300; + missile.avelocity_z=random()*600 - 300; + + setmodel(missile,"progs/stikgren.mdl"); + setsize(missile,'0 0 0','0 0 0'); + setorigin(missile,self.origin+v_forward*16+'0 0 16'); + missile.think=GrenadeExplode2; + missile.nextthink=time + 10; +}; + +void ParticleTesterThink(void) +{ + if(attck_cnt==-1) + remove(self); + particle2(self.origin+'0 0 64', '0 0 0','0 0 0',rint(random()*255+1),attck_cnt,10); + self.think=ParticleTesterThink; + self.nextthink=time + 0.1; +} + +void() ParticleTester= +{ + local entity missile; + attck_cnt=0; + self.lifetime=TRUE; + missile=spawn(); + missile.owner=self; + missile.movetype=MOVETYPE_BOUNCE; + missile.solid=SOLID_BBOX; + missile.velocity=normalize(v_forward)*300; + setmodel(missile,"progs/stikgren.mdl"); + setsize(missile,'0 0 0','0 0 0'); + setorigin(missile,self.origin+v_forward*16+'0 0 16'); + missile.think=ParticleTesterThink; + missile.nextthink=time; +}; + diff --git a/hamthrow.hc b/hamthrow.hc new file mode 100644 index 0000000..eb9eb24 --- /dev/null +++ b/hamthrow.hc @@ -0,0 +1,244 @@ +/* + * $Header: /HexenWorld/Siege/hamthrow.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\warhammer\prjctile\hamthrow.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\warhammer\prjctile +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame HAMMER1 HAMMER2 HAMMER3 HAMMER4 HAMMER5 +$frame HAMMER6 + + + + +// Frame Code +void() frame_HAMMER1 = [ $HAMMER1 , frame_HAMMER2 ] { }; +void() frame_HAMMER2 = [ $HAMMER2 , frame_HAMMER3 ] { }; +void() frame_HAMMER3 = [ $HAMMER3 , frame_HAMMER4 ] { }; +void() frame_HAMMER4 = [ $HAMMER4 , frame_HAMMER5 ] { }; +void() frame_HAMMER5 = [ $HAMMER5 , frame_HAMMER6 ] { }; +void() frame_HAMMER6 = [ $HAMMER6 , frame_HAMMER1 ] { }; + + + + +/*QUAKED hamthrow (1 0 0) (0 0 0) (50 50 50) +New item for QuakeEd + +-------------------------FIELDS------------------------- +-------------------------------------------------------- + +*/ +/* +void() hamthrow = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model2 ("models/hamthrow.mdl"); + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_NONE; + + setmodel (self, "models/hamthrow.mdl"); + self.skin = 0; + + setsize (self, '0 0 0', '50 50 50'); + self.health = 100; +}; + +*/ +// Throwing Hammer +void() ThrowHammerThink = +{ + +if (self.aflag == 1) +{ + if(visible(self.controller)) + { + if (self.effects == 0) + self.effects = 8; + else if (self.effects == 8) + { + self.effects = 4; + sound(self, CHAN_WEAPON, "items/protect3.wav", 0.3, ATTN_NORM); + sprint(self.controller,"Mjolnir Beckons....\n"); + self.wait = self.wait + 1; + } + else if (self.effects == 4) + self.effects = 8; + if (self.wait > 10) + { + sound(self.controller, CHAN_ITEM, "idweapons/pkup.wav",1, ATTN_NORM); + self.controller.amthammer = self.controller.amthammer + 1; + sprint(self.controller,"Mjolnir has magically returned\n"); +// MagicEffect(self.controller); + remove(self); + } + } + else self.effects = 0; + self.nextthink = time + 0.5; +} +else +{ + if (self.aflag == -1) + { + local vector vtemp,dir; + vtemp = self.controller.origin + '0 0 10'; + dir = normalize(vtemp - self.origin); + if (self.watertype < -2) + self.velocity = dir * 150; + else self.velocity = dir * 375; + self.angles = vectoangles(self.velocity); + if (self.flags & FL_ONGROUND)// && self.follow == 0) + { + self.avelocity = '500 0 0'; + self.flags = self.flags - FL_ONGROUND; +// self.follow = 1; + } + } + sound(self, CHAN_WEAPON, "weapons/whoosh.wav", 0.3, ATTN_NORM); +// SpawnFlame(self.origin); + self.nextthink = time + 0.2; +} + if(self.controller.health<=0) + { + GrenadeExplode2(); + remove(self); + } +self.think = ThrowHammerThink; +}; + +void() HammerTouch = +{ +local float inertia; + if (other == self.controller) + { + if (self.aflag!=0||self.bloodloss 2) + missile.velocity = missile.velocity * 300; + else + missile.velocity = missile.velocity * 750; + missile.touch = HammerTouch; + missile.health = 100000; + missile.takedamage = DAMAGE_YES; + missile.th_die = T_MissileTouch; + missile.nextthink = time; + missile.bloodloss = time+2; + missile.think = ThrowHammerThink; + setmodel(missile, "models/hamthrow.mdl"); + setsize(missile,'-1 -2 -4','1 2 4'); +// setsize(missile, VEC_ORIGIN, VEC_ORIGIN); + setorigin(missile, self.origin + v_forward * FL_SWIM + '0 0 16'); + missile.avelocity = '-500 0 0'; + missile.aflag = 0; +// missile.effects = 4; + missile.mass=200; + self.amthammer = self.amthammer - 1; + self.attack_finished=time + 0.5; +}; + diff --git a/head.hc b/head.hc new file mode 100644 index 0000000..3fc27e4 --- /dev/null +++ b/head.hc @@ -0,0 +1,72 @@ +void(string gibname, float dm) ThrowGib; +vector(float dm) VelocityForDamage; +void CorpseThink (void); + + +void () HeadThink = +{ + if ((self.lifetime 20) + return; // too much height change +if ( vlen (self.origin - self.enemy.origin) < 80) + return; // use regular attack + +// charge + SUB_AttackFinished (2); + hknight_char_a1 (); + +}; + +void() CheckContinueCharge = +{ + if (time > self.attack_finished) + { + SUB_AttackFinished (3); + hknight_run1 (); + return; // done charging + } + if (random() > 0.5) + sound (self, CHAN_WEAPON, "knight/sword2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +}; + +//=========================================================================== + +void() hknight_stand1 =[ $stand1, hknight_stand2 ] {ai_stand();}; +void() hknight_stand2 =[ $stand2, hknight_stand3 ] {ai_stand();}; +void() hknight_stand3 =[ $stand3, hknight_stand4 ] {ai_stand();}; +void() hknight_stand4 =[ $stand4, hknight_stand5 ] {ai_stand();}; +void() hknight_stand5 =[ $stand5, hknight_stand6 ] {ai_stand();}; +void() hknight_stand6 =[ $stand6, hknight_stand7 ] {ai_stand();}; +void() hknight_stand7 =[ $stand7, hknight_stand8 ] {ai_stand();}; +void() hknight_stand8 =[ $stand8, hknight_stand9 ] {ai_stand();}; +void() hknight_stand9 =[ $stand9, hknight_stand1 ] {ai_stand();}; + +//=========================================================================== + +void() hknight_walk1 =[ $walk1, hknight_walk2 ] { +hk_idle_sound(); +ai_walk(2);}; +void() hknight_walk2 =[ $walk2, hknight_walk3 ] {ai_walk(5);}; +void() hknight_walk3 =[ $walk3, hknight_walk4 ] {ai_walk(5);}; +void() hknight_walk4 =[ $walk4, hknight_walk5 ] {ai_walk(4);}; +void() hknight_walk5 =[ $walk5, hknight_walk6 ] {ai_walk(4);}; +void() hknight_walk6 =[ $walk6, hknight_walk7 ] {ai_walk(2);}; +void() hknight_walk7 =[ $walk7, hknight_walk8 ] {ai_walk(2);}; +void() hknight_walk8 =[ $walk8, hknight_walk9 ] {ai_walk(3);}; +void() hknight_walk9 =[ $walk9, hknight_walk10 ] {ai_walk(3);}; +void() hknight_walk10 =[ $walk10, hknight_walk11 ] {ai_walk(4);}; +void() hknight_walk11 =[ $walk11, hknight_walk12 ] {ai_walk(3);}; +void() hknight_walk12 =[ $walk12, hknight_walk13 ] {ai_walk(4);}; +void() hknight_walk13 =[ $walk13, hknight_walk14 ] {ai_walk(6);}; +void() hknight_walk14 =[ $walk14, hknight_walk15 ] {ai_walk(2);}; +void() hknight_walk15 =[ $walk15, hknight_walk16 ] {ai_walk(2);}; +void() hknight_walk16 =[ $walk16, hknight_walk17 ] {ai_walk(4);}; +void() hknight_walk17 =[ $walk17, hknight_walk18 ] {ai_walk(3);}; +void() hknight_walk18 =[ $walk18, hknight_walk19 ] {ai_walk(3);}; +void() hknight_walk19 =[ $walk19, hknight_walk20 ] {ai_walk(3);}; +void() hknight_walk20 =[ $walk20, hknight_walk1 ] {ai_walk(2);}; + +//=========================================================================== + +void() hknight_run1 =[ $run1, hknight_run2 ] { +hk_idle_sound(); +ai_run (20); CheckForCharge (); }; +void() hknight_run2 =[ $run2, hknight_run3 ] {ai_run(25);}; +void() hknight_run3 =[ $run3, hknight_run4 ] {ai_run(18);}; +void() hknight_run4 =[ $run4, hknight_run5 ] {ai_run(16);}; +void() hknight_run5 =[ $run5, hknight_run6 ] {ai_run(14);}; +void() hknight_run6 =[ $run6, hknight_run7 ] {ai_run(25);}; +void() hknight_run7 =[ $run7, hknight_run8 ] {ai_run(21);}; +void() hknight_run8 =[ $run8, hknight_run1 ] {ai_run(13);}; + +//============================================================================ + +void() hknight_pain1 =[ $pain1, hknight_pain2 ] {sound (self, CHAN_VOICE, "hknight/pain1.wav", 1, ATTN_NORM);}; +void() hknight_pain2 =[ $pain2, hknight_pain3 ] {}; +void() hknight_pain3 =[ $pain3, hknight_pain4 ] {}; +void() hknight_pain4 =[ $pain4, hknight_pain5 ] {}; +void() hknight_pain5 =[ $pain5, hknight_run1 ] {}; + +//============================================================================ + +void() hknight_die1 =[ $death1, hknight_die2 ] {ai_forward(10);}; +void() hknight_die2 =[ $death2, hknight_die3 ] {ai_forward(8);}; +void() hknight_die3 =[ $death3, hknight_die4 ] +{self.solid = SOLID_NOT; ai_forward(7);}; +void() hknight_die4 =[ $death4, hknight_die5 ] {}; +void() hknight_die5 =[ $death5, hknight_die6 ] {}; +void() hknight_die6 =[ $death6, hknight_die7 ] {}; +void() hknight_die7 =[ $death7, hknight_die8 ] {}; +void() hknight_die8 =[ $death8, hknight_die9 ] {ai_forward(10);}; +void() hknight_die9 =[ $death9, hknight_die10 ] {ai_forward(11);}; +void() hknight_die10 =[ $death10, hknight_die11 ] {}; +void() hknight_die11 =[ $death11, hknight_die12 ] {}; +void() hknight_die12 =[ $death12, hknight_die12 ] {}; + +void() hknight_dieb1 =[ $deathb1, hknight_dieb2 ] {}; +void() hknight_dieb2 =[ $deathb2, hknight_dieb3 ] {}; +void() hknight_dieb3 =[ $deathb3, hknight_dieb4 ] +{self.solid = SOLID_NOT;}; +void() hknight_dieb4 =[ $deathb4, hknight_dieb5 ] {}; +void() hknight_dieb5 =[ $deathb5, hknight_dieb6 ] {}; +void() hknight_dieb6 =[ $deathb6, hknight_dieb7 ] {}; +void() hknight_dieb7 =[ $deathb7, hknight_dieb8 ] {}; +void() hknight_dieb8 =[ $deathb8, hknight_dieb9 ] {}; +void() hknight_dieb9 =[ $deathb9, hknight_dieb9 ] {}; + +void() hknight_die = +{ +// check for gib + if (self.health < -40) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("progs/h_hellkn.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib2.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + return; + } + +// regular death + sound (self, CHAN_VOICE, "hknight/death1.wav", 1, ATTN_NORM); + if (random() > 0.5) + hknight_die1 (); + else + hknight_dieb1 (); +}; + + +//============================================================================ + +void() hknight_magica1 =[ $magica1, hknight_magica2 ] {ai_face();}; +void() hknight_magica2 =[ $magica2, hknight_magica3 ] {ai_face();}; +void() hknight_magica3 =[ $magica3, hknight_magica4 ] {ai_face();}; +void() hknight_magica4 =[ $magica4, hknight_magica5 ] {ai_face();}; +void() hknight_magica5 =[ $magica5, hknight_magica6 ] {ai_face();}; +void() hknight_magica6 =[ $magica6, hknight_magica7 ] {ai_face();}; +void() hknight_magica7 =[ $magica7, hknight_magica8 ] {hknight_shot(-2);}; +void() hknight_magica8 =[ $magica8, hknight_magica9 ] {hknight_shot(-1);}; +void() hknight_magica9 =[ $magica9, hknight_magica10] {hknight_shot(0);}; +void() hknight_magica10 =[ $magica10, hknight_magica11] {hknight_shot(1);}; +void() hknight_magica11 =[ $magica11, hknight_magica12] {hknight_shot(2);}; +void() hknight_magica12 =[ $magica12, hknight_magica13] {hknight_shot(3);}; +void() hknight_magica13 =[ $magica13, hknight_magica14] {ai_face();}; +void() hknight_magica14 =[ $magica14, hknight_run1 ] {ai_face();}; + +//============================================================================ + +void() hknight_magicb1 =[ $magicb1, hknight_magicb2 ] {ai_face();}; +void() hknight_magicb2 =[ $magicb2, hknight_magicb3 ] {ai_face();}; +void() hknight_magicb3 =[ $magicb3, hknight_magicb4 ] {ai_face();}; +void() hknight_magicb4 =[ $magicb4, hknight_magicb5 ] {ai_face();}; +void() hknight_magicb5 =[ $magicb5, hknight_magicb6 ] {ai_face();}; +void() hknight_magicb6 =[ $magicb6, hknight_magicb7 ] {ai_face();}; +void() hknight_magicb7 =[ $magicb7, hknight_magicb8 ] {hknight_shot(-2);}; +void() hknight_magicb8 =[ $magicb8, hknight_magicb9 ] {hknight_shot(-1);}; +void() hknight_magicb9 =[ $magicb9, hknight_magicb10] {hknight_shot(0);}; +void() hknight_magicb10 =[ $magicb10, hknight_magicb11] {hknight_shot(1);}; +void() hknight_magicb11 =[ $magicb11, hknight_magicb12] {hknight_shot(2);}; +void() hknight_magicb12 =[ $magicb12, hknight_magicb13] {hknight_shot(3);}; +void() hknight_magicb13 =[ $magicb13, hknight_run1] {ai_face();}; + +//============================================================================ + +void() hknight_magicc1 =[ $magicc1, hknight_magicc2 ] {ai_face();}; +void() hknight_magicc2 =[ $magicc2, hknight_magicc3 ] {ai_face();}; +void() hknight_magicc3 =[ $magicc3, hknight_magicc4 ] {ai_face();}; +void() hknight_magicc4 =[ $magicc4, hknight_magicc5 ] {ai_face();}; +void() hknight_magicc5 =[ $magicc5, hknight_magicc6 ] {ai_face();}; +void() hknight_magicc6 =[ $magicc6, hknight_magicc7 ] {hknight_shot(-2);}; +void() hknight_magicc7 =[ $magicc7, hknight_magicc8 ] {hknight_shot(-1);}; +void() hknight_magicc8 =[ $magicc8, hknight_magicc9 ] {hknight_shot(0);}; +void() hknight_magicc9 =[ $magicc9, hknight_magicc10] {hknight_shot(1);}; +void() hknight_magicc10 =[ $magicc10, hknight_magicc11] {hknight_shot(2);}; +void() hknight_magicc11 =[ $magicc11, hknight_run1] {hknight_shot(3);}; + +//=========================================================================== + +void() hknight_char_a1 =[ $char_a1, hknight_char_a2 ] {ai_charge(20);}; +void() hknight_char_a2 =[ $char_a2, hknight_char_a3 ] {ai_charge(25);}; +void() hknight_char_a3 =[ $char_a3, hknight_char_a4 ] {ai_charge(18);}; +void() hknight_char_a4 =[ $char_a4, hknight_char_a5 ] {ai_charge(16);}; +void() hknight_char_a5 =[ $char_a5, hknight_char_a6 ] {ai_charge(14);}; +void() hknight_char_a6 =[ $char_a6, hknight_char_a7 ] {ai_charge(20); ai_melee();}; +void() hknight_char_a7 =[ $char_a7, hknight_char_a8 ] {ai_charge(21); ai_melee();}; +void() hknight_char_a8 =[ $char_a8, hknight_char_a9 ] {ai_charge(13); ai_melee();}; +void() hknight_char_a9 =[ $char_a9, hknight_char_a10 ] {ai_charge(20); ai_melee();}; +void() hknight_char_a10=[ $char_a10, hknight_char_a11 ] {ai_charge(20); ai_melee();}; +void() hknight_char_a11=[ $char_a11, hknight_char_a12 ] {ai_charge(18); ai_melee();}; +void() hknight_char_a12=[ $char_a12, hknight_char_a13 ] {ai_charge(16);}; +void() hknight_char_a13=[ $char_a13, hknight_char_a14 ] {ai_charge(14);}; +void() hknight_char_a14=[ $char_a14, hknight_char_a15 ] {ai_charge(25);}; +void() hknight_char_a15=[ $char_a15, hknight_char_a16 ] {ai_charge(21);}; +void() hknight_char_a16=[ $char_a16, hknight_run1 ] {ai_charge(13);}; + +//=========================================================================== + +void() hknight_char_b1 =[ $char_b1, hknight_char_b2 ] +{CheckContinueCharge (); ai_charge(23); ai_melee();}; +void() hknight_char_b2 =[ $char_b2, hknight_char_b3 ] {ai_charge(17); ai_melee();}; +void() hknight_char_b3 =[ $char_b3, hknight_char_b4 ] {ai_charge(12); ai_melee();}; +void() hknight_char_b4 =[ $char_b4, hknight_char_b5 ] {ai_charge(22); ai_melee();}; +void() hknight_char_b5 =[ $char_b5, hknight_char_b6 ] {ai_charge(18); ai_melee();}; +void() hknight_char_b6 =[ $char_b6, hknight_char_b1 ] {ai_charge(8); ai_melee();}; + +//=========================================================================== + +void() hknight_slice1 =[ $slice1, hknight_slice2 ] {ai_charge(9);}; +void() hknight_slice2 =[ $slice2, hknight_slice3 ] {ai_charge(6);}; +void() hknight_slice3 =[ $slice3, hknight_slice4 ] {ai_charge(13);}; +void() hknight_slice4 =[ $slice4, hknight_slice5 ] {ai_charge(4);}; +void() hknight_slice5 =[ $slice5, hknight_slice6 ] {ai_charge(7); ai_melee();}; +void() hknight_slice6 =[ $slice6, hknight_slice7 ] {ai_charge(15); ai_melee();}; +void() hknight_slice7 =[ $slice7, hknight_slice8 ] {ai_charge(8); ai_melee();}; +void() hknight_slice8 =[ $slice8, hknight_slice9 ] {ai_charge(2); ai_melee();}; +void() hknight_slice9 =[ $slice9, hknight_slice10 ] {ai_melee();}; +void() hknight_slice10 =[ $slice10, hknight_run1 ] {ai_charge(3);}; + +//=========================================================================== + +void() hknight_smash1 =[ $smash1, hknight_smash2 ] {ai_charge(1);}; +void() hknight_smash2 =[ $smash2, hknight_smash3 ] {ai_charge(13);}; +void() hknight_smash3 =[ $smash3, hknight_smash4 ] {ai_charge(9);}; +void() hknight_smash4 =[ $smash4, hknight_smash5 ] {ai_charge(11);}; +void() hknight_smash5 =[ $smash5, hknight_smash6 ] {ai_charge(10); ai_melee();}; +void() hknight_smash6 =[ $smash6, hknight_smash7 ] {ai_charge(7); ai_melee();}; +void() hknight_smash7 =[ $smash7, hknight_smash8 ] {ai_charge(12); ai_melee();}; +void() hknight_smash8 =[ $smash8, hknight_smash9 ] {ai_charge(2); ai_melee();}; +void() hknight_smash9 =[ $smash9, hknight_smash10 ] {ai_charge(3); ai_melee();}; +void() hknight_smash10 =[ $smash10, hknight_smash11 ] {ai_charge(0);}; +void() hknight_smash11 =[ $smash11, hknight_run1 ] {ai_charge(0);}; + +//============================================================================ + +void() hknight_watk1 =[ $w_attack1, hknight_watk2 ] {ai_charge(2);}; +void() hknight_watk2 =[ $w_attack2, hknight_watk3 ] {ai_charge(0);}; +void() hknight_watk3 =[ $w_attack3, hknight_watk4 ] {ai_charge(0);}; +void() hknight_watk4 =[ $w_attack4, hknight_watk5 ] {ai_melee();}; +void() hknight_watk5 =[ $w_attack5, hknight_watk6 ] {ai_melee();}; +void() hknight_watk6 =[ $w_attack6, hknight_watk7 ] {ai_melee();}; +void() hknight_watk7 =[ $w_attack7, hknight_watk8 ] {ai_charge(1);}; +void() hknight_watk8 =[ $w_attack8, hknight_watk9 ] {ai_charge(4);}; +void() hknight_watk9 =[ $w_attack9, hknight_watk10 ] {ai_charge(5);}; +void() hknight_watk10 =[ $w_attack10, hknight_watk11 ] {ai_charge(3); ai_melee();}; +void() hknight_watk11 =[ $w_attack11, hknight_watk12 ] {ai_charge(2); ai_melee();}; +void() hknight_watk12 =[ $w_attack12, hknight_watk13 ] {ai_charge(2); ai_melee();}; +void() hknight_watk13 =[ $w_attack13, hknight_watk14 ] {ai_charge(0);}; +void() hknight_watk14 =[ $w_attack14, hknight_watk15 ] {ai_charge(0);}; +void() hknight_watk15 =[ $w_attack15, hknight_watk16 ] {ai_charge(0);}; +void() hknight_watk16 =[ $w_attack16, hknight_watk17 ] {ai_charge(1);}; +void() hknight_watk17 =[ $w_attack17, hknight_watk18 ] {ai_charge(1); ai_melee();}; +void() hknight_watk18 =[ $w_attack18, hknight_watk19 ] {ai_charge(3); ai_melee();}; +void() hknight_watk19 =[ $w_attack19, hknight_watk20 ] {ai_charge(4); ai_melee();}; +void() hknight_watk20 =[ $w_attack20, hknight_watk21 ] {ai_charge(6);}; +void() hknight_watk21 =[ $w_attack21, hknight_watk22 ] {ai_charge(7);}; +void() hknight_watk22 =[ $w_attack22, hknight_run1 ] {ai_charge(3);}; + +//============================================================================ + +void() hk_idle_sound = +{ + if (random() < 0.2) + sound (self, CHAN_VOICE, "hknight/idle.wav", 1, ATTN_NORM); +}; + +void(entity attacker, float damage) hknight_pain = +{ + if (self.pain_finished > time) + return; + + sound (self, CHAN_VOICE, "hknight/pain1.wav", 1, ATTN_NORM); + + if (time - self.pain_finished > 5) + { // allways go into pain frame if it has been a while + hknight_pain1 (); + self.pain_finished = time + 1; + return; + } + + if ((random()*30 > damage) ) + return; // didn't flinch + + self.pain_finished = time + 1; + hknight_pain1 (); +}; + +float hknight_type; + +void() hknight_melee = +{ + hknight_type = hknight_type + 1; + + sound (self, CHAN_WEAPON, "hknight/slash1.wav", 1, ATTN_NORM); + if (hknight_type == 1) + hknight_slice1 (); + else if (hknight_type == 2) + hknight_smash1 (); + else if (hknight_type == 3) + { + hknight_watk1 (); + hknight_type = 0; + } +}; + +/*QUAK-ED monster_hell_knight (1 0 0) (-16 -16 -24) (16 16 40) Ambush +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() monster_hell_knight = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model2 ("progs/hknight.mdl"); + precache_model2 ("progs/k_spike.mdl"); + precache_model2 ("progs/h_hellkn.mdl"); + + + precache_sound2 ("hknight/attack1.wav"); + precache_sound2 ("hknight/death1.wav"); + precache_sound2 ("hknight/pain1.wav"); + precache_sound2 ("hknight/sight1.wav"); + precache_sound ("hknight/hit.wav"); // used by C code, so don't sound2 + precache_sound2 ("hknight/slash1.wav"); + precache_sound2 ("hknight/idle.wav"); + precache_sound2 ("hknight/grunt.wav"); + + precache_sound ("knight/sword1.wav"); + precache_sound ("knight/sword2.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/hknight.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 250; + + self.th_stand = hknight_stand1; + self.th_walk = hknight_walk1; + self.th_run = hknight_run1; + self.th_melee = hknight_melee; + self.th_missile = hknight_magicc1; + self.th_pain = hknight_pain; + self.th_die = hknight_die; + + walkmonster_start (); +}; + diff --git a/holotic.hc b/holotic.hc new file mode 100644 index 0000000..e69de29 diff --git a/horse.hc b/horse.hc new file mode 100644 index 0000000..8d2f0ff --- /dev/null +++ b/horse.hc @@ -0,0 +1,60 @@ +/* + * $Header: /HexenWorld/Siege/horse.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\RdrWar\tsthorse\horse.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\RdrWar\tsthorse +$origin 0 0 0 +$base base skin +$skin skin +$flags 0 + +// +$frame horse + + + + +// Frame Code +void() frame_horse = [ $horse , frame_horse ] { }; + + + + +void() rick_test = +{ + entity rider; + + if (deathmatch) + { + remove(self); + return; + } + + rider = spawn_rider(); + + precache_model2 ("models/horse.mdl"); + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_FLY; + + setmodel (self, "models/horse.mdl"); + self.skin = 0; + + setsize (self, '0 0 0', '50 50 50'); + self.health = 100; + + self.movechain = rider; + rider.origin = self.origin; + rider.flags = rider.flags | FL_MOVECHAIN_ANGLE; + + self.avelocity = '100 100 100'; +}; + diff --git a/hurter.hc b/hurter.hc new file mode 100644 index 0000000..a14b067 --- /dev/null +++ b/hurter.hc @@ -0,0 +1,40 @@ +/* +============================================================================== + +HURTER (jweier) + +============================================================================== +*/ + +void () hurter_touch = +{ + local float damage; + + damage = HRT_BASE_DAMAGE * random(); + + if (other.classname == "player") + { + T_Damage(other, self, self, damage); + } +}; + +void () hurter = +{ + local entity hurt; + + hurt = spawn (); + hurt.owner = self; + hurt.touch = hurter_touch; + hurt.movetype = MOVETYPE_NONE; + hurt.solid = SOLID_NOT; + + //TODO: Make proper size (currently size of Fish) + setsize (self, '-16 -16 -24', '16 16 24'); + + //TODO: Add sound effect if any + //self.noise = "raven/in_hurt.wav"; + + hurt.classname = "hurter"; + + setorigin (hurt, hurt.origin); +}; diff --git a/hydra.hc b/hydra.hc new file mode 100644 index 0000000..596c1df --- /dev/null +++ b/hydra.hc @@ -0,0 +1,842 @@ +/* + * $Header: /HexenWorld/Siege/hydra.hc 3 5/25/98 1:38p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\hydra\final\hydra.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\hydra\final +$origin 0 0 0 +$base base 450 200 +$skin skin1 +$flags 0 + +// +$frame hadie1 hadie2 hadie3 hadie4 hadie5 +$frame hadie6 hadie7 hadie8 hadie9 hadie10 +$frame hadie11 hadie12 hadie13 hadie14 hadie15 +$frame hadie16 hadie17 hadie18 hadie19 hadie20 +$frame hadie21 hadie22 hadie23 hadie24 hadie25 +$frame hadie26 hadie27 hadie28 hadie29 hadie30 +$frame hadie31 hadie32 hadie33 hadie34 hadie35 +$frame hadie36 + +// +$frame hapan1 hapan2 hapan3 hapan4 hapan5 +$frame hapan6 hapan7 hapan8 hapan9 hapan10 + +// +$frame hlft1 hlft2 hlft3 hlft4 hlft5 +$frame hlft6 hlft7 hlft8 hlft9 hlft10 +$frame hlft11 hlft12 hlft13 hlft14 hlft15 +$frame hlft16 hlft17 hlft18 hlft19 hlft20 +$frame hlft21 hlft22 hlft23 hlft24 hlft25 +$frame hlft26 hlft27 hlft28 hlft29 hlft30 + +// +$frame hopen1 hopen2 hopen3 hopen4 hopen5 +$frame hopen6 hopen7 hopen8 + +// +$frame hrit1 hrit2 hrit3 hrit4 hrit5 +$frame hrit6 hrit7 hrit8 hrit9 hrit10 +$frame hrit11 hrit12 hrit13 hrit14 hrit15 +$frame hrit16 hrit17 hrit18 hrit19 hrit20 +$frame hrit21 hrit22 hrit23 hrit24 hrit25 +$frame hrit26 hrit27 hrit28 hrit29 hrit30 + +// +$frame hsdie1 hsdie2 hsdie3 hsdie4 hsdie5 +$frame hsdie6 hsdie7 hsdie8 hsdie9 hsdie10 +$frame hsdie11 hsdie12 hsdie13 hsdie14 hsdie15 +$frame hsdie16 hsdie17 hsdie18 hsdie19 hsdie20 +$frame hsdie21 hsdie22 hsdie23 hsdie24 hsdie25 +$frame hsdie26 hsdie27 hsdie28 hsdie29 hsdie30 +$frame hsdie31 hsdie32 hsdie33 hsdie34 hsdie35 +$frame hsdie36 + +// +$frame hspan1 hspan2 hspan3 hspan4 hspan5 +$frame hspan6 hspan7 hspan8 hspan9 hspan10 + +// +$frame hspit1 hspit2 hspit3 hspit4 hspit5 +$frame hspit6 hspit7 hspit8 hspit9 hspit10 +$frame hspit11 hspit12 + +// +$frame hswim1 hswim2 hswim3 hswim4 hswim5 +$frame hswim6 hswim7 hswim8 hswim9 hswim10 +$frame hswim11 hswim12 hswim13 hswim14 hswim15 +$frame hswim16 hswim17 hswim18 hswim19 hswim20 + +// +$frame htent1 htent2 htent3 htent4 htent5 +$frame htent6 htent7 htent8 htent9 htent10 +$frame htent11 htent12 htent13 htent14 htent15 +$frame htent16 htent17 htent18 htent19 htent20 +$frame htent21 htent22 htent23 htent24 + + + +// Monster Stages +float HYDRA_STAGE_WAIT = 0; +float HYDRA_STAGE_SWIM = 1; +float HYDRA_STAGE_FLOAT = 2; +float HYDRA_STAGE_STRAIGHT = 3; +float HYDRA_STAGE_REVERSE = 4; +float HYDRA_STAGE_CHARGE = 5; +float HYDRA_STAGE_ATTACK = 10; + +void hydra_attack(void); +void hydra_CloseFrames(void); +void hydra_move(float thrust); +void hydra_bob(void); + +void hydra_init(void) +{ // Set the hydra ready for swim + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.think = self.th_run; + thinktime self : random(.1,.6); + self.count = 0; + self.monster_stage = HYDRA_STAGE_SWIM; + self.hydra_FloatTo = 0; + self.goalentity = self.enemy; + + self.monster_awake = TRUE; +} + +void hydra_wait(void) +{ + if (LocateTarget()) + { // We found a target + hydra_init(); + } +} + +// Starting frames for making a large turn +//void hydra_BigLeft(void); +//void hydra_BigRight(void); + +// Starting frames for making a short turn +//void hydra_ShortLeft(void); +//void hydra_ShortRight(void); + +void hydra_OpenFrames(void); +void hydra_TentFrames(void); +void hydra_SpitFrames(void); + +float hydra_check_blind_melee(); + + +void hydra_charge_finish() +{ + self.yaw_speed = 5; + self.cnt = time + random(5,10); + + if (CheckMonsterAttack(MA_MELEE, 3.0)) + { + self.monster_stage += HYDRA_STAGE_ATTACK; + self.monster_check = 0; + self.think = hydra_attack; + thinktime self : 0.05; + return; + } + + self.monster_stage = HYDRA_STAGE_SWIM; + self.think = self.th_run; + thinktime self : 0.1; +} + +void hydra_charge() +{ + float dist; + + self.yaw_speed = 8; + + check_pos_enemy(); + + ai_face(); + + dist = vlen(self.enemy.origin - self.origin); + + movetogoal(dist / 8); + + if (range(self.enemy) == RANGE_MELEE) + { + self.monster_check = 0; + hydra_charge_finish(); + return; + } + + if (self.hydra_chargeTime < time) + { + self.monster_check = 0; + hydra_charge_finish(); + return; + } + + self.think = hydra_charge; + thinktime self : 0.05; +} + +float hydra_check_blind_melee(void) +{ + float dist, c1;//, c2; + + if (self.enemy.watertype != CONTENT_WATER) return 0; + if (self.cnt > time) return 0; + + dist = vhlen(self.enemy.origin - self.origin); + + traceline(self.origin, self.enemy.origin, FALSE, self); + + c1 = fov(self, self.enemy, 80); + + if ((dist < 256) && c1 && trace_ent == self.enemy) + { + if (random() < 0.2) + return 1; + } + + return 0; +} + +void hydra_blind(void) +{ + stuffcmd (self.enemy, "df\n"); + + self.hydra_chargeTime = time + 1; + self.think = hydra_charge; + thinktime self : 0.05; +} + +void hydra_checkForBlind(void) +{ + float r; + + r = pointcontents(self.enemy.origin); + + if (r != CONTENT_WATER) + { + self.think = self.th_run; + thinktime self : 0.1; + return; + } + + r = vhlen(self.enemy.origin - self.origin); + + if ((r < 256) && (fov(self, self.enemy, 80)) && (fov(self.enemy, self, 80))) + { + thinktime self : 0.1; + self.think = hydra_blind; + } + else + { + self.think = self.th_run; + thinktime self : 0.1; + } +} + +void hydra_swim(float thrust) +{ + float dist; + float temp; + + if (self.velocity) self.velocity = self.velocity * 0.7; + + if (!self.enemy.flags2 & FL_ALIVE) + { + self.goalentity = self.enemy = world; + self.monster_stage = HYDRA_STAGE_WAIT; + return; + } + + dist = (4.0 + thrust*6); // Movement distance this turn + + movetogoal(dist); + + if (self.hydra_FloatTo == 0) + { + dist = self.enemy.origin_z - self.origin_z; + if (dist < -50) self.hydra_FloatTo = dist - random(60); + else if (dist > 50) self.hydra_FloatTo = dist + random(60); + } + + if (self.hydra_FloatTo < -10) + { + temp = random(-3.5,-2.5); +// movestep(0,0,temp, FALSE); + self.hydra_FloatTo -= temp; + } + else if (self.hydra_FloatTo > 10) + { + temp = random(2.5,3.5); +// movestep(0,0,temp, FALSE); + self.hydra_FloatTo -= temp; + } + else self.hydra_FloatTo = 0; + + self.th_save = self.think; + + //checkenemy(); + + enemy_range = range (self.enemy); + if (hydra_check_blind_melee()) + { + self.monster_check = 2; + hydra_attack(); + } + + dist = vlen(self.enemy.origin - self.origin); + if (dist > 350) + { + if (CheckMonsterAttack(MA_MISSILE,8.0)) + return; + } + else + CheckMonsterAttack(MA_MELEE,3.0); +} + +void hydra_float(void) +{ + float Length; + + if (self.velocity) self.velocity = self.velocity * 0.7; + + Length = vhlen(self.origin - self.enemy.origin); + + if (Length < 300.0) + { + self.monster_stage = HYDRA_STAGE_SWIM; + self.hydra_FloatTo = 0; + return; + } + + /*self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + ChangeYaw();*/ + ai_face(); + + self.th_save = self.think; + enemy_range = range (self.enemy); + if (hydra_check_blind_melee()) + { + self.monster_check = 2; + hydra_attack(); + } + CheckMonsterAttack(MA_MISSILE,8.0); +} + +void hydra_reverse(void) +{ + float retval; + float dist; + + self.monster_duration -= 1; + dist = 4.0; // Movement distance this turn + + retval = walkmove(self.angles_y + 180, dist, FALSE); + /*if (!retval) + { + self.ideal_yaw = FindDir(); + self.monster_duration = 0;//random(40,70); + self.monster_stage = HYDRA_STAGE_STRAIGHT; + ChangeYaw();//hydra_turn(200); + return; + }*/ + + //self.monster_stage = HYDRA_STAGE_FLOAT; + +} + +void hydra_move(float thrust) +{ + check_pos_enemy(); + + if (self.monster_stage == HYDRA_STAGE_SWIM) + { + hydra_swim(thrust); + return; + } + else if (self.monster_stage == HYDRA_STAGE_FLOAT) + { + hydra_float(); + return; + } + else if (self.monster_stage == HYDRA_STAGE_WAIT) + { + hydra_wait(); + return; + } + else if (self.monster_stage == HYDRA_STAGE_REVERSE) + { +// hydra_reverse(); + return; + } +} + +void hydra_attack(void) +{ + if (self.monster_check > 0) + { + hydra_SpitFrames(); + } + else + { + hydra_TentFrames(); + } +} + +void hydra_fire(void) +{ + sound (self, CHAN_WEAPON, "hydra/spit.wav", 1, ATTN_NORM); + do_spit('0 0 0'); + do_spit('0 0 0'); + do_spit('0 0 0'); +} + +void hydra_tent(float TryHit) +{ + ai_face(); + + check_pos_enemy(); + + if (TryHit) + { + makevectors(self.angles); + traceline(self.origin,self.origin+v_forward*128,FALSE,self); + + if (trace_ent.takedamage) + { + sound (self, CHAN_WEAPON, "hydra/tent.wav", 1, ATTN_NORM); + T_Damage (trace_ent, self, self, random(1,2)); + } + else + movetogoal(15); + } +} + +void hydra_open(void) +{ + ai_face(); +} + +void hydra_bob(void) +{ + local float rnd1, rnd2, rnd3; +// local vector vtmp1, modi; + + rnd1 = self.velocity_x + random(-10,10); + rnd2 = self.velocity_y + random(-10,10); + rnd3 = self.velocity_z + random(10); + + if (rnd1 > 10) + rnd1 = 10; + if (rnd1 < -10) + rnd1 = -10; + + if (rnd2 > 10) + rnd2 = 10; + if (rnd2 < -10) + rnd2 = -10; + +/* if (rnd3 < 10) + rnd3 = 15;*/ + if (rnd3 > 55) + rnd3 = 50; + + self.velocity_x = rnd1; + self.velocity_y = rnd2; + self.velocity_z = rnd3; +} + +// Swimming +float hydra_Swim[20] = +{ + -0.2, + -0.1, + 0.0, + 0.1, // Top going down + 0.2, + 0.3, + 0.4, + 0.5, // middle + 0.4, + 0.3, + 0.2, + 0.1, // bottom + 0.0, + -0.1, + -0.2, + -0.3, + -0.4, + -0.5, // middle + -0.4, + -0.3 +}; + +// Top = 1, tr = 2, br = 3, tl = 4, bl = 5 +float hydra_TentAttacks[24] = +{ + 0, + 0, + 0, + 0, + 1, + 0, + 3, + 0, + 4, + 0, + 0, + 5, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 4, + 3, + 1, + 0, + 0 +}; + + + + + + + + + + + + + + + + + + + +// Attacking others +void hydra_AttackDieFrames(void) +{ + self.think = hydra_AttackDieFrames; + thinktime self : HX_FRAME_TIME; + + if (self.frame != $hadie36) + AdvanceFrame($hadie1,$hadie36); + + if (self.frame == $hadie35) + { + self.solid = SOLID_NOT; + MakeSolidCorpse(); + } + + if (self.frame >= $hadie13) + hydra_bob(); + + if(self.health<-30) + chunk_death(); +} + +void hydra_AttackPainFrames(void) +{ + self.think = hydra_AttackPainFrames; + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($hapan1,$hapan10); +} + +// Swimming others +void hydra_SwimDieFrames(void) +{ + self.think = hydra_SwimDieFrames; + thinktime self : HX_FRAME_TIME; + + if (self.frame != $hsdie36) + AdvanceFrame($hsdie1,$hsdie36); + + if (self.frame == $hsdie35) + { + self.solid = SOLID_NOT; + MakeSolidCorpse(); + } + + if (self.frame >= $hsdie8) + hydra_bob(); + + if(self.health<-30) + chunk_death(); +} + +void hydra_SwimPainFrames(void) +{ + self.think = hydra_SwimPainFrames; + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($hspan1,$hspan10); +} + +// Attacking +void hydra_OpenFrames(void) +{ + self.think = hydra_OpenFrames; + thinktime self : HX_FRAME_TIME; + + if (self.enemy.watertype != CONTENT_WATER) + { + self.monster_stage = HYDRA_STAGE_FLOAT; + self.think = self.th_run; + thinktime self : 0.1; + + return; + } + + hydra_open(); + if (AdvanceFrame($hopen1,$hopen8) == AF_END) + { + hydra_attack(); + } +} + +void hydra_CloseFrames(void) +{ + self.think = hydra_CloseFrames; + thinktime self : HX_FRAME_TIME; + + if (RewindFrame($hopen8,$hopen1) == AF_END) + { + self.monster_stage -= HYDRA_STAGE_ATTACK; + self.think = self.th_save; + } +} + +void hydra_SpitFrames(void) +{ + vector vecA,vecB; + + self.think = hydra_SpitFrames; + thinktime self : HX_FRAME_TIME; + + self.angles_y = vectoyaw(self.enemy.origin - self.origin); + + if (AdvanceFrame($hspit1,$hspit12) == AF_END) + { + self.think = hydra_CloseFrames; + self.monster_check = -1; + } + else if (self.frame == $hspit7 && self.monster_check == 2) + { + sound (self, CHAN_WEAPON, "hydra/spit.wav", 1, ATTN_NORM); + vecA = self.enemy.origin - self.origin + self.enemy.proj_ofs; + vecA = vectoangles(vecA); + makevectors(vecA); + v_forward_z = 0 - v_forward_z; + + vecA = v_factor('-40 400 -40'); + vecB = v_factor('40 500 40'); + + particle2(self.origin+v_forward*40,vecA,vecB,256,12,400); + self.think = hydra_checkForBlind; + thinktime self : 0.1; + } + else if (self.frame == $hspit8 && self.monster_check == 1) + { + hydra_fire(); + } +} + +void hydra_TentFrames(void) +{ + float r; + + if (!self.enemy.flags2 & FL_ALIVE) + { + self.goalentity = self.enemy = world; + self.monster_stage = HYDRA_STAGE_WAIT; + self.think = self.th_stand; + thinktime self : 0.1; + return; + } + + self.think = hydra_TentFrames; + thinktime self : 0.025; + + if (AdvanceFrame($htent1,$htent24) == AF_END) + { + r = range(self.enemy); + if ((r == RANGE_MELEE) && (random(0, 1) < 0.3)) + { + self.frame = $htent1; + hydra_tent(hydra_TentAttacks[self.frame - $htent1]); + } + else + self.think = hydra_CloseFrames; + } + else + { + hydra_tent(hydra_TentAttacks[self.frame - $htent1]); + } +} + +// Regular swimming / movement +void hydra_SwimFrames(void) +{ + self.think = hydra_SwimFrames; + thinktime self : HX_FRAME_TIME; + + AdvanceFrame($hswim1,$hswim20); + if (self.frame == $hswim1) + sound (self, CHAN_WEAPON, "hydra/swim.wav", 1, ATTN_NORM); + + hydra_move((hydra_Swim[self.frame - $hswim1]) + 0.3); +} + +/*QUAKED misc_fountain (0 1 0.8) (0 0 0) (32 32 32) +New item for QuakeEd + +-------------------------FIELDS------------------------- +angles 0 0 0 the direction it should move the particles +movedir 1 1 1 the force it should move them +color 256 the color +cnt 2 the number of particles each time +-------------------------------------------------------- + +*/ +void misc_fountain(void) +{ + starteffect(CE_FOUNTAIN, self.origin, self.angles,self.movedir,self.color,self.cnt); +} + +void do_hydra_spit(void) +{ + self.monster_check = 1; + self.monster_stage += HYDRA_STAGE_ATTACK; + + sound (self, CHAN_WEAPON, "hydra/open.wav", 1, ATTN_NORM); + hydra_OpenFrames(); +} + +void do_hydra_tent(void) +{ + self.monster_check = 0; + self.monster_stage += HYDRA_STAGE_ATTACK; + + sound (self, CHAN_WEAPON, "hydra/open.wav", 1, ATTN_NORM); + hydra_OpenFrames(); +} + +void do_hydra_die(void) +{ + self.flags (+) FL_SWIM; + + sound (self, CHAN_WEAPON, "hydra/die.wav", 1, ATTN_NORM); + + if (self.monster_stage >= HYDRA_STAGE_ATTACK) + hydra_AttackDieFrames(); + else + hydra_SwimDieFrames(); +} + +void hydra_retreat() +{ + self.monster_stage = HYDRA_STAGE_REVERSE; + self.think = self.th_run; + thinktime self : 0.1; +} + +void hydra_pain(entity attacker, float damage) +{ + sound (self, CHAN_WEAPON, "hydra/pain.wav", 1, ATTN_NORM); +} + +void init_hydra(void) +{ + if (deathmatch) + { + remove(self); + return; + } + + self.monster_stage = HYDRA_STAGE_WAIT; + + precache_model ("models/hydra.mdl"); + precache_model ("models/spit.mdl"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_SWIM; + self.thingtype=THINGTYPE_FLESH; + self.classname="monster_hydra"; + self.mass = 7; + + setmodel (self, "models/hydra.mdl"); + self.skin = 0; + + setsize (self, '-30 -30 -24', '30 30 24'); + self.hull = HULL_SCORPION; +//self.hull = HULL_HYDRA; + self.health = 125; + self.experience_value = 50; + self.mintel = 4; + + self.th_stand = hydra_SwimFrames; + self.th_walk = hydra_SwimFrames; + self.th_run = hydra_SwimFrames; + self.th_pain = hydra_pain; + self.th_die = do_hydra_die; + self.th_missile = do_hydra_spit; + self.th_melee = do_hydra_tent; + + self.takedamage = DAMAGE_YES; + self.flags2 (+) FL_ALIVE; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 5; + self.view_ofs = '0 0 0'; + self.use = monster_use; + + self.flags (+) FL_SWIM | FL_MONSTER; + + self.pausetime = 99999999; + + total_monsters += 1; + + thinktime self : random(0.5); + self.think = self.th_stand; +} + + +/*QUAKED monster_hydra (1 0.3 0) (-40 -40 -42) (40 40 42) STAND HOVER JUMP PLAY_DEAD DORMANT +New item for QuakeEd + +-------------------------FIELDS------------------------- +NOTE: Normal QuakEd monster spawnflags don't apply here (no_jump, play_dead, no_drop) +-------------------------------------------------------- + +*/ +void monster_hydra(void) +{ + init_hydra(); + + precache_sound("hydra/pain.wav"); + precache_sound("hydra/die.wav"); + precache_sound("hydra/open.wav"); + precache_sound("hydra/turn-s.wav"); + precache_sound("hydra/turn-b.wav"); + precache_sound("hydra/swim.wav"); + precache_sound("hydra/tent.wav"); + precache_sound("hydra/spit.wav"); +} + diff --git a/ice_imp.hc b/ice_imp.hc new file mode 100644 index 0000000..e69de29 diff --git a/icemace.hc b/icemace.hc new file mode 100644 index 0000000..be3df21 --- /dev/null +++ b/icemace.hc @@ -0,0 +1,652 @@ +/* + * $Header: /HexenWorld/Siege/icemace.hc 19 6/01/98 2:49a Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\icestaff\final\icestaff.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\icestaff\final +$origin 10 -10 10 +$base BASE skin +$skin skin +$skin skin2 +$flags 0 + +// +$frame fire1a fire1b fire1c +$frame fire2a fire2b fire2c +$frame fire3a fire3b fire3c +$frame fire4a fire4b fire4c +$frame fire5a fire5b fire5c + +// +$frame idle1 idle2 idle3 idle4 idle5 +$frame idle6 idle7 idle8 idle9 idle10 +$frame idle11 idle12 idle13 idle14 idle15 +$frame idle16 + +// +$frame power1 power2 power3 power4 power5 +$frame power6 power7 power8 power9 + +// +$frame select1 select2 select3 select4 select5 +$frame select6 select7 select8 select9 select10 + +void() IceCubeThink = +{ + if(self.freeze_time144) + { + self.colormap-=1; + self.abslight-=0.05; + } + else + { + self.colormap=0; + self.abslight=0.5; + self.skin=GLOBAL_SKIN_ICE; + } + + if(random()<0.2&&random()<0.2) + sound(self,CHAN_AUTO,"misc/drip.wav",1,ATTN_NORM); + + self.think=IceCubeThink; + thinktime self : 0.1; +}; + +void (entity loser,entity forwhom) SnowJob= +{ +//FIXME: Make gradual- person slows down then stops +entity oself; + if(loser.solid==SOLID_BSP) + return; + + if(coop) + if(loser.classname=="player"&&forwhom.classname=="player") + return; + + if(teamplay) + if(loser.team==forwhom.team) + return; + + if(loser.flags&FL_MONSTER&&loser.monsterclass>=CLASS_BOSS) + { + T_Damage(loser,self,forwhom,10); + return; + } + + sound(loser,CHAN_BODY,"crusader/frozen.wav",1,ATTN_NORM); + loser.frozen=50; + loser.oldskin=loser.skin; + if(loser.classname!="player") + { + loser.colormap=159; + loser.thingtype=THINGTYPE_ICE; + loser.freeze_time=time+5; + if(loser.scale==0) + loser.scale = 1; + loser.lifetime=loser.scale; + loser.o_angle=loser.mins; + loser.v_angle=loser.maxs; + loser.enemy=forwhom; + loser.oldthink=loser.think; + loser.think=IceCubeThink; + thinktime loser : 0; + loser.touch=SUB_Null; + loser.th_pain=SUB_Null; + loser.wait = time + 3; + if(loser.angles_x==0&&loser.angles_z==0) + loser.drawflags(+)SCALE_ORIGIN_BOTTOM; + loser.oldmovetype=loser.movetype; + loser.movetype=MOVETYPE_TOSS; + loser.health=1; + loser.deathtype="ice melt"; + loser.th_die=shatter; +// AwardExperience(forwhom,loser,loser.experience_value); + loser.experience_value=0; + oself=self; + self=loser; + SUB_UseTargets(); + self=oself; + } + else + { + loser.credit_enemy=forwhom;//give credit to freezer + loser.artifact_active(+)ARTFLAG_FROZEN; + loser.colormap=159; + loser.thingtype=THINGTYPE_ICE; + loser.o_angle=loser.v_angle; + loser.pausetime = time + 10; + loser.attack_finished = time + 10; +//Temp -turns screen blue + loser.health=1; + thinktime loser : 10; +//Prevent interruption? loser.th_pain=SUB_Null; + } + loser.flags(-)FL_FLY; + loser.flags(-)FL_SWIM; + if(loser.flags&FL_ONGROUND) + loser.last_onground=time; + loser.flags(-)FL_ONGROUND; +//need to be able to reverse this... + loser.oldtouch=loser.touch; + loser.touch=obj_push; + loser.drawflags(+)DRF_TRANSLUCENT|MLS_ABSLIGHT; + loser.abslight=1; +}; + +/*void FreezeDie() +{ + // FIXME - get all of this stuff over + //particleexplosion(self.origin,14,10,10); + //particle2(self.origin,'-10 -10 -10','10 10 10',145,14,5); + //if(self.movechain!=world) + // remove(self.movechain); + remove(self); +}*/ + +void remove_artflag () +{ + if(self.enemy.frozen<=0) + { + self.enemy.artifact_active(-)self.artifact_active; + } + remove(self); +} + +void() FreezeTouch= +{ + float hitType; + float removeBall; + + removeBall = 0; + + if(other==self.owner) + return; + + //starteffect(CE_ICE_HIT,self.origin-self.movedir*8); + if(other.takedamage&&other.health&&other.frozen<=0&&other.thingtype==THINGTYPE_FLESH)//FIXME: Thingtype_flesh only + { // hit someone who MIGHT be frozen by this attack - should always be players + //sound (self, CHAN_BODY, "crusader/icehit.wav", 1, ATTN_NORM); + + hitType = 0; + + if(other.freeze_time<=time) + { + other.frozen=0; + } + other.freeze_time=time+2.5; + other.frozen-=1.5; + if(other.classname=="player") + { + other.artifact_active(+)ARTFLAG_FROZEN; + newmis=spawn(); + newmis.enemy=other; + newmis.artifact_active=ARTFLAG_FROZEN; + newmis.think=remove_artflag; + thinktime newmis : 0.3; + } + + + if(other.flags&FL_COLDHEAL)//Had to take out cold heal, so cold resist + { + T_Damage(other,self,self.owner,9); + } + else if((other.health<=10||(other.classname=="player"&&other.frozen<=-7&&other.health<200))&&other.solid!=SOLID_BSP&&!other.artifact_active&ART_INVINCIBILITY&&other.thingtype==THINGTYPE_FLESH&&other.health<100) + { + SnowJob(other,self.owner); + } + else + { + T_Damage(other,self,self.owner,20); + } + removeBall = 1; + } + else if(other.frozen<=0) + { // hit a wall, I think + //sound (self, CHAN_BODY, "crusader/icewall.wav", 1, ATTN_NORM); + hitType = 1; + T_RadiusDamage(self,self.owner,30,self.owner); + self.touch=SUB_Null; + //shatter(); + //remove(self); + removeBall = 1; + } + else + { + hitType = 1; + //sound(self,CHAN_BODY,"misc/tink.wav",1,ATTN_NORM); + } + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_ICEHIT); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 8); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 8); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 8); + WriteByte (MSG_MULTICAST, hitType); + multicast(self.origin,MULTICAST_PVS); + + if(removeBall) + { + remove(self); + } +}; + +void iceballThink(void) +{ + self.movedir = normalize(self.velocity); + + self.angles = vectoangles(self.movedir); + + traceline(self.origin, self.origin + self.movedir * 360.0, FALSE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_ICESHOT); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 100); + multicast(self.origin,MULTICAST_PVS); + + thinktime self : 0.3; + + if (self.lifetime < time) + SUB_Remove(); + +} + +void()FireFreeze= +{ + +//vector dir; + self.bluemana-=3; + self.attack_finished=time + 0.2; + self.punchangle_x= -1; + makevectors (self.v_angle); + //sound (self, CHAN_WEAPON, "crusader/icefire.wav", 1, ATTN_NORM); + weapon_sound(self, "crusader/icefire.wav"); + newmis = spawn (); + newmis.owner = self; + newmis.movetype = MOVETYPE_BOUNCEMISSILE; + newmis.solid = SOLID_BBOX; + + newmis.th_die=shatter; + newmis.deathtype="ice shatter"; + + newmis.touch = FreezeTouch; + newmis.classname = "snowball"; + newmis.speed = 1200; + newmis.movedir=normalize(v_forward); + newmis.angles = vectoangles(self.movedir); + newmis.velocity = newmis.movedir * newmis.speed; + newmis.scale = newmis.scale * 1.5; + newmis.lifetime = time + 4; + + setmodel (newmis, "models/iceshot1.mdl"); + + setsize (newmis, '0 0 0', '0 0 0'); + setorigin (newmis, self.origin+self.proj_ofs + v_forward*8); + + //newmis.effects(+)EF_ICEBALL_EFFECT; + newmis.effects(+)EF_NODRAW; + + entity oldself; + oldself = self; + self = newmis; + + newmis.think = iceballThink; + newmis.think(); + + self = oldself; +}; + +void() blizzard_think= +{ + entity loser; + vector dir, top; + + if(self.lifetime=10) + icestaff_blizzard(); + else if(!self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=1) + FireFreeze(); + else + icestaff_idle(); +} + +void icestaff_f2 (void) +{ + self.th_weapon=icestaff_f2; + self.wfs = advanceweaponframe($fire2a,$fire2c); + if (self.wfs==WF_CYCLE_WRAPPED) + if(!self.button0) + icestaff_idle(); + else + icestaff_shard(); + else if (self.attack_finished<=time&&self.weaponframe==$fire2a) + if(self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=10) + icestaff_blizzard(); + else if(!self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=1) + FireFreeze(); + else + icestaff_idle(); +} + +void icestaff_f3 (void) +{ + self.th_weapon=icestaff_f3; + self.wfs = advanceweaponframe($fire3a,$fire3c); + if (self.wfs==WF_CYCLE_WRAPPED) + if(!self.button0) + icestaff_idle(); + else + icestaff_shard(); + else if (self.attack_finished<=time&&self.weaponframe==$fire3a) + if(self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=10) + icestaff_blizzard(); + else if(!self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=1) + FireFreeze(); + else + icestaff_idle(); +} + +void icestaff_f4 (void) +{ + self.th_weapon=icestaff_f4; + self.wfs = advanceweaponframe($fire4a,$fire4c); + if (self.wfs==WF_CYCLE_WRAPPED) + if(!self.button0) + icestaff_idle(); + else + icestaff_shard(); + else if (self.attack_finished<=time&&self.weaponframe==$fire4a) + if(self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=10) + icestaff_blizzard(); + else if(!self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=1) + FireFreeze(); + else + icestaff_idle(); +} + +void icestaff_f5 (void) +{ + self.th_weapon=icestaff_f5; + self.wfs = advanceweaponframe($fire5a,$fire5c); + if (self.wfs==WF_CYCLE_WRAPPED) + if(!self.button0) + icestaff_idle(); + else + icestaff_shard(); + else if (self.attack_finished<=time&&self.weaponframe==$fire5a) + if(self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=10) + icestaff_blizzard(); + else if(!self.artifact_active&ART_TOMEOFPOWER&&self.bluemana>=1) + FireFreeze(); + else + icestaff_idle(); +} + +void icestaff_shard (void) +{ +float r; + r=rint(random(4)) + 1; + if(r==1) + icestaff_f1(); + else if(r==2) + icestaff_f2(); + else if(r==3) + icestaff_f3(); + else if(r==4) + icestaff_f4(); + else + icestaff_f5(); +} + +void Cru_Ice_Fire (void) +{ + if(self.artifact_active&ART_TOMEOFPOWER) + icestaff_blizzard(); + else + icestaff_shard(); +} + diff --git a/iceshot.hc b/iceshot.hc new file mode 100644 index 0000000..9f701d7 --- /dev/null +++ b/iceshot.hc @@ -0,0 +1,234 @@ +void() rain_use; + +void() IceCubeThink = +{ + if((self.maxs_z-self.mins_z)>5) + if(pointcontents(self.origin-'0 0 23')==CONTENT_LAVA||self.frozen<=0) + { + if((self.maxs_z-self.mins_z)<25) + self.small=TRUE; + self.frozen=FALSE; + self.think=self.oldthink; + self.nextthink=time; + self.skin=self.oldskin; + self.touch=self.oldtouch; + self.movetype=self.oldmovetype; + self.drawflags-=DRF_TRANSLUCENT; + return; + } + + if(pointcontents(self.origin)==CONTENT_WATER||pointcontents(self.origin)==CONTENT_SLIME) + { + self.frozen=self.frozen - 1; + self.scale -= 0.01; + } + + if((!self.flags&FL_ONGROUND)&&pointcontents(self.origin+'0 0 -24')!=CONTENT_SOLID) + self.frags=TRUE; + if (self.frags&&(self.flags&FL_ONGROUND)) + T_Damage(self,world,self.enemy,self.frags*10); + self.frozen=self.frozen - 0.2; + if(self.wait<=time) + { + self.scale -= 0.007; + self.mins = self.o_angle * (self.scale/self.lifetime); + self.maxs = self.v_angle * (self.scale/self.lifetime); + setsize(self,self.mins,self.maxs); + droptofloor(); + } + if((self.maxs_z-self.mins_z)<=5||self.scale<=0.07) + { +// AwardExperience(self.enemy,self,0); + remove(self); + } + self.think=IceCubeThink; + self.nextthink=time+0.1; +}; + +void (entity loser,entity forwhom) SnowJob= +{ + sound(loser,CHAN_AUTO,"weapons/frozen.wav",1,ATTN_NORM); + loser.frozen=50; + loser.oldskin=loser.skin; + loser.skin=105; + if(loser.classname!="player") + { + if(loser.scale==0) + loser.scale = 1; + loser.lifetime=loser.scale; + loser.o_angle=loser.mins; + loser.v_angle=loser.maxs; + loser.enemy=forwhom; + loser.oldthink=loser.think; + loser.think=IceCubeThink; + loser.nextthink=time; +// loser.nextthink=time+30; + loser.touch=SUB_Null; +//Prevent interruption? loser.th_pain=SUB_Null; + loser.wait = time + 10; + if(loser.angles_x==0&&loser.angles_z==0) + loser.drawflags+=SCALE_ORIGIN_BOTTOM; + loser.oldmovetype=loser.movetype; + loser.movetype=MOVETYPE_PUSHPULL; + loser.health=1; + } + else + { + loser.o_angle=loser.v_angle; + loser.pausetime = time + 20; + loser.attack_finished = time + 20; +//Temp -turns screen blue + loser.items+= IT_QUAD; + loser.health=1; + loser.nextthink=time + 20; +//Prevent interruption? loser.th_pain=SUB_Null; + } + if(loser.flags&FL_FLY) + loser.flags = loser.flags - FL_FLY; + if (loser.flags & FL_SWIM) + loser.flags = loser.flags - FL_SWIM; + if(loser.flags&FL_ONGROUND) + loser.flags = loser.flags - FL_ONGROUND; +//need to be able to reverse this... + loser.oldtouch=loser.touch; + loser.touch=obj_push; + loser.drawflags+=DRF_TRANSLUCENT; +}; + +void() FreezeTouch= +{ + if(other.takedamage&&other.health&&(!other.frozen)&&(!other.flags&FL_COLDRESIST)&&(!other.flags&FL_COLDHEAL)) + { + if((!other.frozen)&&other.health>12) + T_Damage(other,self,self.owner,10); + if(random()<0.2) + SnowJob(other,self.owner); + } + else if(other.flags&FL_COLDHEAL) + other.health=other.health+5; + else + T_RadiusDamage(self,self.owner,30,self.owner); + self.touch=SUB_Null; + self.deathtype="ice shatter"; + shatter(); +}; + +void()FreezeThink= +{ + if((pointcontents(self.origin)==CONTENT_WATER&&random()<0.3)||pointcontents(self.origin)==CONTENT_LAVA||(pointcontents(self.origin)==CONTENT_SLIME&&random()<0.5)||self.wait 0. if so, come back alive +//This could happen by magic or by fire for fire imp or cold for ice imp + else if(self.health>0) + { + self.takedamage = DAMAGE_YES; + self.flags (+) FL_FLY; + self.flags2 (+) FL_ALIVE; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_FLY; + if(self.classname=="monster_imp_lord") + { + setsize (self, '-32 -32 0', '32 32 56'); + self.hull=HULL_SCORPION; + } + else + { + setsize (self, '-16 -16 0', '16 16 36'); + self.hull=HULL_CROUCH; + } + self.th_stand (); + return; + } + else + { + self.think=imp_die; + if (self.frame == $death7 || self.frame == $death8 ) // when cycling between these 2 frames during falling, make him flutter more randomly + thinktime self : random(0.05,0.217); + else + thinktime self : HX_FRAME_TIME; + } +} + +void imp_die_init () +{ + setsize (self, '-16 -16 0', '16 16 24'); + self.hull=HULL_CROUCH; + imp_die(); +} + +void imp_up_down() +{ // Function to make the imp randomly change height +vector end_vec,vec1; + +// dprint("CHECKING UP/DOWN\n"); + if (self.velocity_z > -10.0 && self.velocity_z < 10.0) + { // If we aren't moving up/down that much, maybe we want to change altitudes + self.velocity_z = 0.0; + if (random() < 0.3||self.attack_state==AS_SLIDING) + { // Should we change altitudes? + makevectors (self.angles); + if (random() < 0.5) + { // Go Down + vec1 = self.origin + v_up*-48; + traceline (self.origin,vec1,FALSE,self); + if(trace_fraction==1) + { + end_vec=vec1+v_forward*32; + traceline (vec1,end_vec,FALSE,self); + if (trace_fraction == 1||random()<0.5) + { + //dprint("Goin down\n"); + self.velocity_z = self.speed*-7; + } + } + } + else + { // Go Up + vec1 = self.origin + v_up*88; + traceline (self.origin,vec1,FALSE,self); + if(trace_fraction==1) + { + end_vec=vec1+v_forward*32; + traceline (vec1,end_vec,FALSE,self); + if (trace_fraction == 1||random()<0.5) + { + //dprint("Goin up\n"); + self.velocity_z = self.speed*7; + } + } + } + self.flags(-)FL_ONGROUND; + } + } +} + +void imp_ferry () +{ +float dist; +vector org; + movetogoal(self.speed); +/* + if(!check_z_move(self.level)) + imp_up_down(); +*/ + self.velocity_z=self.goalentity.origin_z-self.origin_z; + if(fabs(self.velocity_z)>self.speed*30) + if(self.velocity_z<0) + self.velocity_z=self.speed*-30; + else + self.velocity_z=self.speed*30; + self.flags(-)FL_ONGROUND; +// dprintf("Boost : %s\n",self.velocity_z); + + org=self.goalentity.origin; + dist=vlen(self.origin-org); + if(dist<=self.size_x) + { + imp_drop(); + return; + } + + org=self.enemy.origin; + org_z=self.enemy.absmax_z; + dist=vlen(self.origin-org); + if(dist>200) + { + imp_drop(); + return; + } + else + self.enemy.velocity=normalize(self.origin-org)*dist*5; + self.enemy.angles=self.angles; + + MonsterCheckContents(); +} + +void imp_pick_up (void) +{ + self.attack_state=AS_FERRY; + self.goalentity=find(world,targetname,self.target); + self.enemy.flags(+)FL_FLY; +} + +void imp_set_speeds () +{ +float anglediff,dist; + if(pointcontents(self.origin+self.view_ofs)==CONTENT_WATER) + dist=4; + else + dist=8; //Movement distance this turn + + anglediff= fabs(self.angles_y - self.ideal_yaw); //How far we're trying to turn + + if (anglediff > 20) // If it is a big distance to turn, then don't move as far forward + dist = dist / 1.5; + + self.level=imp_fly_amounts[self.frame - $impfly1]; + self.speed = dist + self.level*4*self.scale; //tweaks to speed based on anim frame + + if(!visible(self.enemy)) + { + if(self.mintel) + SetNextWaypoint(); + if(self.search_time=77&&enemy_hdist<=77) + { +// dprint("too close!\n"); + return TRUE; + } + return FALSE; +} + +void imp_move () +{ +float too_close; + if((self.strength==3&&self.enemy==self.controller&&vlen(self.enemy.origin-self.origin)<128)||(self.goalentity==world||self.enemy==world)) + { + self.think=self.th_stand; + return; + } + + if(self.attack_state!=AS_FERRY) + checkenemy(); + + self.velocity=self.velocity*(1/1.05); + if(imp_check_too_close()) + { + self.ideal_yaw=self.angles_y; + too_close=TRUE; + } + else + ai_face(); + + imp_set_speeds(); + + if(self.attack_state==AS_FERRY) + { + imp_ferry(); + return; + } + +/* if(self.goalentity.classname=="waypoint") + { + dprint("Following waypoints"); + if(self.search_time=time) + { + enemy_vis=visible(self.enemy); + if(!enemy_vis||!clear_path(self.enemy,FALSE)) + { + vector go_dir; + float r,minspeed,maxspeed; + makevectors(self.angles); + minspeed=100*self.scale; + maxspeed=300*self.scale; + r=random(); + if(r<0.25) + go_dir=check_axis_move(v_right,minspeed,maxspeed); + else if(r<=0.5) + go_dir=check_axis_move(v_up,minspeed,maxspeed); + else if(r<=0.75) + go_dir=check_axis_move((v_right+v_up)*0.5,minspeed,maxspeed); + else + go_dir=check_axis_move((v_right*-1+v_up)*0.5,minspeed,maxspeed); + if(go_dir!='0 0 0') + { + if(r<0.25) + { + self.velocity_x=go_dir_x; + self.velocity_y=go_dir_y; + } + else if(r<=0.5) + self.velocity_z=go_dir_z; + else + self.velocity=go_dir; + self.flags(-)FL_ONGROUND; + } + } + } + + if(self.spawnflags&PICKUP) + if(random()<0.2) + if(self.target!="") + if(self.origin_z>self.enemy.absmax_z - 8) + if(vlen(self.enemy.origin+self.enemy.proj_ofs-self.origin)<=self.size_x*1.5) + imp_pick_up(); + + MonsterCheckContents(); +} + +float imp_new_action () +{ +float too_close; + enemy_vis=visible(self.enemy); + too_close=imp_check_too_close(); + if((random()<0.7&&self.enemy.flags2&FL_ALIVE)||!enemy_vis||too_close||self.attack_state==AS_FERRY) + { + if(self.think!=imp_fly&&self.enemy!=world) + { + self.think=imp_fly; + thinktime self : 0; + return TRUE; + } + return FALSE; + } + else + { + if(self.think!=imp_hover) + { + self.think=imp_hover; + thinktime self : 0; + return TRUE; + } + return FALSE; + } + return FALSE; +} + +void imp_strafe_left () [++ $impfly1 .. $impfly20] +{ +vector dir; + ai_face(); + if(cycle_wrapped) + { + self.think=imp_fly; + thinktime self : 0; + return; + } +// else if(self.frame==$impfly1) +// dprint("strafing left\n"); + makevectors(self.angles); + dir='0 0 0' - (v_right*(self.frame - $impfly1)*30); + self.velocity_x=dir_x; + self.velocity_y=dir_y; + check_pos_enemy(); +//FIXME: check for attack? +} + +void imp_strafe_right () [++ $impfly1 .. $impfly20] +{ +vector dir; + ai_face(); + if(cycle_wrapped) + { + self.think=imp_fly; + thinktime self : 0; + return; + } +// else if(self.frame==$impfly1) +// dprint("strafing right\n"); + makevectors(self.angles); + dir=v_right*(self.frame - $impfly1)*30; + self.velocity_x=dir_x; + self.velocity_y=dir_y; + check_pos_enemy(); +//FIXME: check for attack? +} + +void imp_rise () [++ $impfly1 .. $impfly20] +{ + check_pos_enemy(); + if(self.frame==$impfly1) + { +// dprint("shooting up\n"); + self.attack_finished=time+1.7; + self.velocity_z=600; + } + else if(self.frame>$impfly14 &&self.attack_finished 0.1) + { + imp_strafe_left();//Left because you want to go away from it + return TRUE; + } + else if( dot < -0.1) + { + imp_strafe_right(); + return TRUE; + } + dot = proj_spot_dir * v_up; + if ( dot > 0.2) + { + imp_dive(); + return TRUE; + } + else if( dot < 0) + { + imp_rise(); + return TRUE; + } +// dprint("no defense dir found\n"); + return FALSE; + } + return FALSE; +} + +void imp_missile () +{ + if(self.skin==1) + { + weapon_sound(self, "imp/shard.wav"); +// sound (self, CHAN_WEAPON, "imp/shard.wav", 1, ATTN_NORM); + + makevectors (self.angles); + do_shard('14 8 0'*self.scale,360 + random()*150, '0 0 0'); + do_shard('14 8 0'*self.scale,360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + do_shard('14 8 0'*self.scale,360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); +/* if (random() < 0.5) + do_shard('14 8 0'*self.scale,360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + if (random() < 0.5) + do_shard('14 8 0'*self.scale,360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + if (random() < 0.5) + do_shard('14 8 0'*self.scale,360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); +*/ } + else + { + weapon_sound(self, "imp/fireball.wav"); +// sound (self, CHAN_WEAPON, "imp/fireball.wav", 1, ATTN_NORM); + do_fireball('14 8 0'*self.scale); + } +} + +void imp_melee () +{ +vector org,destiny; +float dist,damg; + makevectors(self.angles); + org=self.origin+self.proj_ofs+v_forward*16*self.scale; + destiny=(self.enemy.absmin+self.enemy.absmax)*0.5; + dist=vlen(destiny-org); + traceline(org,destiny,FALSE,self); + if(dist>48*self.scale||trace_fraction==1) + { + imp_missile(); + return; + } + if(trace_ent.takedamage) + { + string hitsound; + if(self.strength==3) + { + if(trace_ent.thingtype==THINGTYPE_FLESH) + MeatChunks (trace_endpos,v_right*random(-100,-300)+'0 0 200', 3,trace_ent); + hitsound="weapons/slash.wav"; + } + else + hitsound="assassin/chntear.wav"; + sound(trace_ent,CHAN_AUTO,hitsound,1,ATTN_NORM); + if(self.strength==3) + damg=40; + else + damg=10*self.scale; + T_Damage(trace_ent,self,self,damg); + } + else + hitsound="weapons/gauntht2.wav"; + SpawnPuff(trace_endpos,v_right*-100,10*self.scale,trace_ent); + weapon_sound(self, hitsound); +// sound(self,CHAN_AUTO,hitsound,1,ATTN_NORM); +} + +void imp_attack(void) +{ + self.last_attack=time; + if (vlen(self.origin-self.enemy.origin) <= 64*self.scale) + { + self.v_angle=self.angles; + imp_melee (); + } + else + imp_missile(); +} + +void imp_attack_anim() [++ $impfir1 .. $impfir21] +{ + check_pos_enemy(); + + ai_face(); + + if(imp_check_defense()) + return; + + if (self.frame == $impfir17) + imp_attack(); + else if (cycle_wrapped) + { + self.think=imp_fly; + if(visible(self.enemy)&&self.enemy.flags2&FL_ALIVE) + if(random()<0.2+skill/10) + self.think=imp_attack_anim; + self.attack_finished=time + 1; + thinktime self : 0; + } +} + +void imp_abort_swoop () [++ $swpout1 .. $swpout15] +{ + check_pos_enemy(); + if(self.velocity_x>10) + self.velocity_x/=2; + else + self.velocity_x=0; + + if(self.velocity_x>10) + self.velocity_y/=2; + else + self.velocity_y=0; + + if(self.frame==$swpout15) + { + self.attack_finished=time + 1; + self.think=imp_fly; + thinktime self : 0; + } +} + +void imp_swoop_end () [++ $swpend1 .. $swpend15] +{ + check_pos_enemy(); + self.flags (-) FL_ONGROUND; + + // swoop him back up and slow down his forward velocity (xy) + self.velocity_z += 15; + self.velocity_x /= 1.2; + self.velocity_y /= 1.2; + + if (self.frame == $swpend15) + { // Finished swooping + self.attack_finished=time + 1; + self.velocity = '0 0 0'; + self.yaw_speed = 8; + self.think=imp_hover; + thinktime self : 0; + } +} + +void imp_swoop_charge () [++ $swpcyc1 .. $swpcyc4] +{ +vector dir,destiny,org; + self.last_attack=time; + check_pos_enemy(); + destiny=self.enemy.origin+self.enemy.proj_ofs; + org=(self.absmin+self.absmax)*0.5; + enemy_vis=visible(self.enemy); + enemy_infront=infront(self.enemy); + enemy_range=vlen(destiny - org); + if(self.enemy.last_attack>time - 1 &&fov(self,self.enemy,45)) + { + self.velocity_z+=150; + imp_abort_swoop(); + } + else if(enemy_vis&&enemy_infront&&enemy_range<2000) + { + dir=normalize(destiny-org); + self.velocity=dir*(377+self.count*7); + ai_face(); + + self.count += 1; + + if (self.flags & FL_ONGROUND || self.count > 30) + { // Didn't hit our target, so go back up + self.flags (-) FL_ONGROUND; + imp_abort_swoop(); + } + } + else + imp_abort_swoop(); +} + +void imp_enter_swoop () [++ $swoop1 .. $swoop20] +{ +vector vec,org; + check_pos_enemy(); + if(self.frame==$swoop1) + { + self.yaw_speed=15; + self.count=140; + self.touch = imp_touch; + self.velocity = '0 0 0'; + + if(self.strength==3) + { + sound (self, CHAN_VOICE, "imp/swoopbig.wav", 1, ATTN_NORM); + } + else + { + sound (self, CHAN_VOICE, "imp/swoop.wav", 1, ATTN_NORM); + } + } + + ai_face(); + self.count *= 1.15; + + if (self.frame >= $swoop12) + { // Start to swoop down + org=self.origin; + org_z=self.absmin_z; + vec = normalize(self.enemy.origin - org + self.enemy.proj_ofs); + self.velocity = vec*self.count; + if (self.frame <= $swoop13 ) + { // If we haven't pulled out yet, keep going straight down + self.velocity_x = self.velocity_y = 0; + } + if(self.absmin_z - self.enemy.absmax_z>50&&self.frame==$swoop13) + self.frame=$swoop12; + } + + if (self.frame == $swoop12 || self.frame == $swoop13 ) + { // Swoop down cycling frames + if (self.flags & FL_ONGROUND) + { // Ran into something on the way down + self.flags (-) FL_ONGROUND; + self.frame = $swoop14; + self.count = 280; + } + if (self.origin_z - self.enemy.origin_z < 60) + { // Have to flatten out soon + self.frame = $swoop14; + self.count = 280; + } + } + + if(self.frame==$swoop20) + { + self.count=0; + self.think=imp_swoop_charge; + thinktime self : 0.05; + } +} + +void imp_straight_swoop () [-- $swpout15 .. $swpout1] +{ + check_pos_enemy(); + ai_face(); + if(imp_check_defense()) + return; + + if(self.frame==$swpout15) + { + self.yaw_speed=15; + self.count=140; + self.velocity = '0 0 0'; + self.touch = imp_touch; + if(self.strength==3) + { + sound (self, CHAN_VOICE, "imp/swoopbig.wav", 1, ATTN_NORM); + } + else + { + sound (self, CHAN_VOICE, "imp/swoop.wav", 1, ATTN_NORM); + } + } + + if(self.frame==$swpout1) + { + self.count=0; + self.think=imp_swoop_charge; + thinktime self : 0.05; + } +} + +void() imp_touch = +{ +float damg,damg_plus; +vector punch,dir; + + + self.touch=SUB_Null; + if((self.frame >= $swpcyc1 && self.frame <= $swpcyc4 )||(self.frame>=$swoop16 &&self.frame<=$swoop20)) + { // If we are in swoop attack frames + self.flags (-) FL_ONGROUND; + weapon_sound(self, "imp/swoophit.wav"); +// sound (self, CHAN_WEAPON, "imp/swoophit.wav", 1, ATTN_NORM); + + self.think=imp_swoop_end; + if (other.takedamage) + { // We sucessfully hit something + + if(self.frame >= $swpcyc1 && self.frame <= $swpcyc4) + damg_plus=self.count; + else + damg_plus=(self.frame-$swoop16)*5; + + if(self.classname == "monster_imp_lord") + { + damg = (33 + (damg_plus *5)); + T_Damage (other, self, self.controller, damg); + if(other.monsterclass400) + { + makevectors(self.angles); + SpawnPuff(self.origin+self.proj_ofs+v_forward*self.absmax_x,'0 0 0',10,self); + self.pain_finished=-666; + self.think=self.th_pain; + } + self.velocity=other.velocity;//?? + } + else if(vlen(self.velocity)>300) + { + weapon_sound(self, "imp/swoophit.wav"); +// sound (self, CHAN_WEAPON, "imp/swoophit.wav", 1, ATTN_NORM); + } +}; + +float imp_check_attack () +{ +float enemy_hdist,enemy_zdiff,swoop_no_drop; +vector destiny,org; + if(self.enemy==world) + { + self.think=self.th_stand; + return FALSE; + } + + if(self.enemy==self.controller||self.enemy==self) + if(!FindMonsterTarget())//if(!LocateTarget()) + return FALSE; + + if(self.attack_state==AS_FERRY) + return FALSE; + + enemy_vis=visible(self.enemy); + if (!enemy_vis) + { + if(self.mintel) + SetNextWaypoint(); + if(self.search_time70+30*self.scale&&(enemy_zdiff>36||swoop_no_drop)) + { + tracearea(org,org-'0 0 1'*enemy_zdiff,min,max,FALSE,self); + if(trace_fraction==1||swoop_no_drop) + { + if(swoop_no_drop) + tracearea(org,destiny,min,max,FALSE,self); + else + tracearea(org-'0 0 1'*enemy_zdiff,destiny,min,max,FALSE,self); + if(trace_ent==self.enemy) + { + if(swoop_no_drop) + self.think=imp_straight_swoop; + else + self.think=imp_enter_swoop; + thinktime self : 0; + return TRUE; + } + } + } + } + + if(self.strength==0)//fire imps attack less- try to get close + if(random()<0.5) + return FALSE; + + self.think=imp_attack_anim; + thinktime self : 0; + return TRUE; +} + +void imp_hover () [++ $impfly1 .. $impfly20] +{ +float too_close; + if (self.frame == $impfly1) + { + if(pointcontents(self.origin+self.view_ofs)==CONTENT_WATER) + self.noise="hydra/turn-s.wav"; + else if(self.strength==3) + self.noise="imp/flybig.wav"; + else + self.noise="imp/fly.wav"; + sound (self, CHAN_BODY, self.noise, 1, ATTN_NORM); + } + + if(self.strength==3) + if(!self.controller.flags2&FL_ALIVE||self.controller.imp_count!=self.imp_count) + { + self.think=summoned_imp_die; + thinktime self : 0; + return; + } + + if(self.enemy) + if(self.attack_state!=AS_FERRY) + checkenemy(); + + if(!self.enemy||(self.enemy==self.controller&&self.strength==3)) + if(imp_find_target()) + return; + + if(self.enemy) + { + self.velocity=self.velocity*(1/1.05); + ai_face(); + imp_set_speeds(); + check_z_move(self.level); + + if(imp_check_defense()) + return; + + if(imp_check_attack()) + return; + + if(self.enemy!=world) + { + too_close=imp_check_too_close(); + enemy_vis=visible(self.enemy); + if(!enemy_vis||too_close||self.attack_state!=AS_STRAIGHT) + { + self.think=imp_fly; + thinktime self : 0; + return; + } + } + } + + if(self.enemy!=world||self.goalentity!=world) + if(imp_new_action()) + return; + + MonsterCheckContents(); +} + +void() stone_imp_awaken = [++ $impup7 .. $impup23] +{ + if(self.frame==$impup10) + { + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.count = 0; + setsize (self, '-16 -16 0', '16 16 36'); + self.origin_z-=14; + self.hull=HULL_CROUCH; + self.mass = 3; + self.health=self.max_health; + self.flags (+) FL_MONSTER | FL_FLY; + self.movetype = MOVETYPE_FLY; + self.takedamage=DAMAGE_YES; + self.touch= SUB_Null; + self.th_die = imp_die_init; + self.spawnflags (-) SF_IMP_DORMANT; + + self.artifact_active (-) ARTFLAG_STONED; + weapon_sound(self, "fx/wallbrk.wav"); +// sound (self, CHAN_VOICE, "fx/wallbrk.wav", 1, ATTN_NORM); + while(chunk_cnt < CHUNK_MAX) + { + CreateModelChunks(self.size,.7); + chunk_cnt+=1; + } + self.skin=self.oldskin; + if(self.skin) + self.classname="monster_imp_ice"; + else + self.classname="monster_imp_fire"; + + self.thingtype=THINGTYPE_FLESH; + self.scale=1; + } + else if(self.frame==$impup23) + self.think=imp_fly; +}; + +void imp_pain_anim2 () [++ $impup6 .. $impup14] +{ + check_pos_enemy(); + ai_pain(2); + if(self.frame==$impup14) + { + self.touch=SUB_Null; + self.think=imp_hover; + thinktime self : 0; + } +} + +void imp_pain_anim1 () [-- $impup14 .. $impup6] +{ + check_pos_enemy(); + ai_pain(2); + if(self.frame==$impup6) + { + self.think=imp_pain_anim2; + thinktime self : 0; + } +} + +void(entity attacker, float damage) imp_pain = +{ + if(self.monster_awake) + if(self.pain_finished>time) + return; + + if(self.targetname!=""&&self.strength==2) + { + self.think=SUB_Null; + self.nextthink=-1; + return; + } + + if(random()<0.5&&self.pain_finished!=-666&&attacker!=world&&self.touch!=SUB_Null&&self.monster_awake)//FIXME: make more logical + return; + + self.monster_awake=TRUE; + + self.pain_finished=time+3;//only react to pain once every 3 seconds max + + if(self.attack_state==AS_FERRY&&random()<0.2) + imp_drop(); + +//FIXME: pain sound + if (self.spawnflags & SF_IMP_DORMANT) + { + self.frame=$impup1; + self.think=stone_imp_awaken; + } + else + { + if(self.strength==3) + { + sound (self, CHAN_VOICE, "imp/upbig.wav", 1, ATTN_NORM); + } + else + { + sound (self, CHAN_VOICE, "imp/up.wav", 1, ATTN_NORM); + } + + self.think=imp_pain_anim1; + } + thinktime self : 0; +}; + +void imp_use (void) +{ + self.use=SUB_Null; + self.targetname=""; + + if(activator.classname=="player") + self.enemy=self.goalentity=activator; + else + dprint("ERROR: monster not activated by player!\n"); + + self.frame=$impup1; + self.think=stone_imp_awaken; + thinktime self : random(); +} + +float imp_find_target(void) +{ // Imp in waiting state + if(FindMonsterTarget())//if (LocateTarget()) + { // We found a target + if (self.strength==2) + { + float self_infront, self_vis, enemy_dist, r1, r2; + self_infront=infront_of_ent(self,self.enemy); + self_vis=visible2ent(self,self.enemy); + enemy_dist=vlen(self.origin-self.enemy.origin); + r1=random(); + r2=random(); + if((self_infront&&self_vis&&r1<0.1&&r2<0.5&&enemy_dist<1000)||enemy_dist<=RANGE_MELEE) + { + self.goalentity = self.enemy; + self.think=stone_imp_awaken; + thinktime self : 0; + return TRUE; + } + else + { + self.goalentity=self.enemy=world; + return FALSE; + } + } + else + { + self.goalentity = self.enemy; + self.think = self.th_run; + thinktime self : 0; + return TRUE; + } + } + else if(self.classname=="monster_imp_lord") + self.enemy=self.goalentity=self.controller; + return FALSE; +} + +void imp_wait() [++ $impwat1 .. $impwat24] +{ + + if(self.strength==2) + self.frame=$impwat1; + else if(!self.flags&FL_ONGROUND) + { + self.think=imp_hover; + thinktime self : 0; + } + + if(random()<0.5) + if(imp_find_target()) + return; +} + +void imp_fly () [++ $impfly1 .. $impfly20] +{ + if (self.frame == $impfly1) + { + if(pointcontents(self.origin+self.view_ofs)==CONTENT_WATER) + self.noise="hydra/turn-s.wav"; + else if(self.strength==3) + self.noise="imp/flybig.wav"; + else + self.noise="imp/fly.wav"; + sound (self, CHAN_BODY, self.noise, 1, ATTN_NORM); + } + + if(self.strength==3) + if(!self.controller.flags2&FL_ALIVE||self.controller.imp_count!=self.imp_count) + { + self.think=summoned_imp_die; + thinktime self : 0; + return; + } + + imp_move(); + + if(imp_check_defense()) + return; + + if(imp_check_attack()) + return; + + if(imp_new_action()) + return; +} + +void imp_awaken () [++ $impup1 .. $impup23] +{ + if (self.frame == $impup1) + if(self.strength==3) + { + sound (self, CHAN_VOICE, "imp/upbig.wav", 1, ATTN_NORM); + } + else + { + sound (self, CHAN_VOICE, "imp/up.wav", 1, ATTN_NORM); + } + + check_pos_enemy(); + movestep(0,0,imp_up_amounts[self.frame - $impup1], FALSE); + walkmove(self.angles_y, imp_up_amounts[self.frame - $impup1] / 2.0, FALSE); + + if (self.frame == $impup23) + { + self.think = imp_fly; + thinktime self : 0; + } +} + +void impmonster_start_go () +{ + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 5.0; + if(!self.use) + self.use = monster_use; + + self.pausetime = 99999999; + + if(self.targetname!="") + { + self.frame=$impwat1; + self.think=imp_use; + self.nextthink=-1; + } + else if(self.enemy!=world) + imp_awaken(); + else + self.th_stand(); +} + +void impmonster_start () +{ + thinktime self : random(0.5); + + self.think = impmonster_start_go; + total_monsters = total_monsters + 1; +} + +void init_imp (float which_skin) +{ + if (deathmatch&&self.wait!=-1&&self.classname!="monster_imp_lord") + { + remove(self); + return; + } + + if(!self.flags2&FL_SUMMONED) + { + precache_model ("models/imp.mdl"); + precache_model ("models/h_imp.mdl");//empty for now + if (self.classname == "monster_imp_lord") + { + precache_model ("models/shardice.mdl"); + precache_model ("models/fireball.mdl"); + precache_sound("imp/upbig.wav"); + precache_sound("imp/diebig.wav"); + precache_sound("imp/swoopbig.wav"); + precache_sound("imp/flybig.wav"); + } + else + { + precache_sound("imp/up.wav"); + precache_sound("imp/die.wav"); + precache_sound("imp/swoop.wav"); + precache_sound("imp/fly.wav"); + if (self.classname == "monster_imp_ice") + precache_model ("models/shardice.mdl"); + else + precache_model ("models/fireball.mdl"); + } + precache_sound("imp/swoophit.wav"); + precache_sound("imp/fireball.wav"); + precache_sound("imp/shard.wav"); + precache_sound("hydra/turn-s.wav"); + } + + self.solid = SOLID_SLIDEBOX; + setmodel (self, "models/imp.mdl"); + if (self.classname == "monster_imp_lord") + { + self.drawflags(+)SCALE_ORIGIN_CENTER; + self.scale=2.3;//2? +// setsize (self, '-32 -32 -32', '32 32 32'); + setsize (self, '-40 -40 -50', '40 40 50'); + self.hull=HULL_GOLEM;//HYDRA; + self.view_ofs=self.proj_ofs='0 0 82'; + } + else + { + self.scale=1; + setsize (self, '-16 -16 0', '16 16 36'); + self.view_ofs=self.proj_ofs='0 0 33'; + self.hull=HULL_CROUCH; + } + self.headmodel = "models/h_imp.mdl"; + + if(which_skin==1) + self.flags (+) FL_COLDHEAL; + else + self.flags (+) FL_FIREHEAL; + + if(self.wait!=-1) + { + self.movetype = MOVETYPE_FLY; + self.takedamage=DAMAGE_YES; + + self.strength = which_skin; + self.impType = which_skin; + + self.flags2 (+) FL_ALIVE; + self.thingtype=THINGTYPE_FLESH; + if (self.classname == "monster_imp_lord") + { + self.max_health=self.health = 600; + self.experience_value = self.init_exp_val = 3000; + self.mass = 10; + self.th_die = summoned_imp_die; + } + else + { + self.max_health=self.health = 75+self.strength*25; + self.experience_value = 400 +self.strength*100; + self.mass = 3; + self.th_die = imp_die_init; + } + self.mintel = 5; + + if (self.spawnflags & MONSTER_HOVER) + { + self.th_stand = imp_hover; + self.th_walk = imp_fly; + } + else + { + self.th_stand = imp_wait; + self.th_walk = imp_awaken; + } + self.th_run = self.th_walk; + self.th_pain = imp_pain; + self.th_missile = imp_enter_swoop; + self.th_melee = imp_attack; + } + + self.yaw_speed=8; + self.speed=10; + self.attack_state = AS_STRAIGHT; + self.level=0; + + if (self.spawnflags & SF_IMP_DORMANT) + { + self.classname="gargoyle"; + self.scale=1.5; + self.artifact_active (+) ARTFLAG_STONED; + setsize (self, '-16 -16 -14', '16 16 22'); + self.origin_z+=14; + self.hull=HULL_CROUCH; + self.takedamage=DAMAGE_NO_GRENADE; + self.thingtype=THINGTYPE_GREYSTONE; + self.movetype=MOVETYPE_PUSHPULL; + self.touch=obj_push; + self.health+=100; + self.mass=100; + self.th_die = chunk_death; + if(self.wait!=-1) + { + self.use = imp_use; + self.oldskin = self.skin; + self.th_stand = imp_wait; + } + self.strength=2; + } + else + self.flags (+) FL_MONSTER | FL_FLY; + + total_monsters += 1; + if(self.enemy) + self.th_run(); + else if(self.wait!=-1) + impmonster_start(); + else + self.frame = $impwat1; +} + +/*QUAKED monster_imp_ice (1 0.3 0) (-16 -16 0) (16 16 55) STAND HOVER x x gargoyle +Grunt monster - common. Shoots multiple ice shards. Can only be killed by defrosting it. +immune to ice attacks + +gargoyle = uses the grey stone texture to make it look like a gargoyl- will wake up if the player looks at him long enough, gets close, or hurts him. +-------------------------FIELDS------------------------- +wait = if you give it a -1, the gargoyle will not come alive, it's just a decoration +-------------------------------------------------------- + +*/ +void monster_imp_ice () +{ + init_imp(1); +} + +/*QUAKED monster_imp_fire (1 0.3 0) (-16 -16 0) (16 16 55) STAND HOVER x x gargoyle +Grunt monster - common. Shoots a fireball. Can only be killed by defrosting it. + +gargoyle = uses the grey stone texture to make it look like a gargoyl- will wake up if the player looks at him long enough, gets close, or hurts him. +-------------------------FIELDS------------------------- +wait = if you give it a -1, the gargoyle will not come alive, it's just a decoration +-------------------------------------------------------- + +*/ +void monster_imp_fire () +{ + init_imp(0); +} + +/*QUAKED monster_imp_lord (1 0.3 0) (-16 -16 0) (16 16 55) STAND HOVER x x gargoyle +Big imp dude- kicks butt and takes names + +gargoyle = uses the grey stone texture to make it look like a gargoyl- will wake up if the player looks at him long enough, gets close, or hurts him. +-------------------------FIELDS------------------------- +wait = if you give it a -1, the gargoyle will not come alive, it's just a decoration +-------------------------------------------------------- + +*/ +void monster_imp_lord () +{ + if(self.flags2&FL_SUMMONED) + self.spawnflags(+)MONSTER_HOVER; + init_imp(3); +} diff --git a/impulse.hc b/impulse.hc new file mode 100644 index 0000000..94b66e6 --- /dev/null +++ b/impulse.hc @@ -0,0 +1,648 @@ +/* + * $Header: /HexenWorld/Siege/impulse.hc 29 6/01/98 2:49a Mgummelt $ + */ + +void PlayerAdvanceLevel(float NewLevel); +void player_level_cheat(void); +void player_experience_cheat(void); +void Polymorph (entity loser); +//void create_swarm (void); + +void restore_weapon () +{//FIXME: use idle, not select + self.weaponframe = 0; + if (self.playerclass==CLASS_PALADIN) + { + if (self.weapon == IT_WEAPON1) + if(self.flags2&FL2_EXCALIBUR) + self.weaponmodel = "models/v_excal.mdl"; + else + self.weaponmodel = "models/vorpal.mdl"; + else if (self.weapon == IT_WEAPON2) + self.weaponmodel = "models/axe.mdl"; + else if (self.weapon == IT_WEAPON3) + self.weaponmodel = "models/xbow2.mdl"; + } + else if (self.playerclass==CLASS_CRUSADER) + { + if (self.weapon == IT_WEAPON1) + self.weaponmodel = "models/warhamer.mdl"; + else + self.weaponmodel = "models/icestaff.mdl"; + } + else if (self.playerclass==CLASS_NECROMANCER) + { + if (self.weapon == IT_WEAPON1) + self.weaponmodel = "models/sickle.mdl"; + else if (self.weapon == IT_WEAPON2) + self.weaponmodel = "models/xbow2.mdl"; + else + self.weaponmodel = "models/spllbook.mdl"; // FIXME: still need these models + } + else if (self.playerclass==CLASS_ASSASSIN) + { + if (self.weapon == IT_WEAPON1) + self.weaponmodel = "models/punchdgr.mdl"; + else if (self.weapon == IT_WEAPON2) + self.weaponmodel = "models/xbow2.mdl"; + else if (self.weapon == IT_WEAPON3) + self.weaponmodel = "models/crossbow.mdl"; + else if (self.weapon == IT_WEAPON4) + self.weaponmodel = "models/v_assgr.mdl"; + } + else if (self.playerclass==CLASS_SUCCUBUS) + { + if (self.weapon == IT_WEAPON1) + self.weaponmodel = "models/sucwp1.mdl"; + else if (self.weapon == IT_WEAPON2) + self.weaponmodel = "models/vorpal.mdl"; + else if (self.weapon == IT_WEAPON3) + self.weaponmodel = "models/xbow2.mdl"; + else if (self.weapon == IT_WEAPON4) + self.weaponmodel = "models/v_assgr.mdl"; + } + else if (self.playerclass==CLASS_DWARF) + { + if (self.weapon == IT_WEAPON1) + self.weaponmodel = "models/warhamer.mdl"; + else if (self.weapon == IT_WEAPON2) + self.weaponmodel = "models/axe.mdl"; + } +} + +void see_coop_view () +{ +entity startent,found; +float gotone; + if(self.viewentity!=self) + centerprint(self,"Ally vision not available in chase camera mode\n"); + + if(!coop&&!teamplay) + { + centerprint(self,"Ally vision not available\n"); + return; + } + + if(self.cameramode==world) + startent=self; + else + startent=self.cameramode; + found=startent; + while(!gotone) + { + found=find(found,classname,"player"); + if(found.flags&FL_CLIENT) + if((deathmatch&&teamplay&&found.team==self.team)||coop) + if(found.cameramode==world||found==self) + gotone=TRUE; + if(found==startent) + { + centerprint(self,"No allies available\n"); + return; + } + } + + if(found==self) + { + CameraReturn(); + return; + } + centerprint(self,found.netname); + AllyVision(self,found); + self.weaponmodel=self.cameramode.weaponmodel; + self.weaponframe=self.cameramode.weaponframe; +} + + + +void player_everything_cheat(float override) +{ + if((deathmatch||coop)&&!override) + return; + + CheatCommand(override); // Give them weapons and mana + +// Artifact_Cheat(); // Give them all artifacts + + self.puzzles_cheat = 1; // Get them past puzzles + + // Then they leave home and never call you. The ingrates. +} + + +void PrintFrags() +{ +entity lastent; + lastent=nextent(world); + while(lastent) + { + if(lastent.classname=="player") + { + bprint(PRINT_MEDIUM, lastent.netname); + bprint(PRINT_MEDIUM, " (L-"); + bprint(PRINT_MEDIUM, ftos(lastent.level)); + if(lastent.playerclass==CLASS_ASSASSIN) + bprint(PRINT_MEDIUM, " Assassin) "); + else if(lastent.playerclass==CLASS_PALADIN) + bprint(PRINT_MEDIUM, " Paladin) "); + else if(lastent.playerclass==CLASS_CRUSADER) + bprint(PRINT_MEDIUM, " Crusader) "); + else + bprint(PRINT_MEDIUM, " Necromancer) "); + bprint(PRINT_MEDIUM, " FRAGS: "); + bprint(PRINT_MEDIUM, ftos(lastent.frags)); + bprint(PRINT_MEDIUM, " (LF: "); + bprint(PRINT_MEDIUM, ftos(lastent.level_frags)); + bprint(PRINT_MEDIUM, ")\n"); + } + lastent=find(lastent,classname,"player"); + } +} + + +/*void()gravityup = +{ + self.gravity+=0.01; + if(self.gravity==10) + self.gravity=0; + dprint(PRINT_MEDIUM, "Gravity: "); + dprint(PRINT_MEDIUM, ftos(self.gravity)); + dprint(PRINT_MEDIUM, "\n"); +}; + +void()gravitydown = +{ + self.gravity-=0.01; + if(self.gravity==-10) + self.gravity=0; + dprint(PRINT_MEDIUM, "Gravity: "); + dprint(PRINT_MEDIUM, ftos(self.gravity)); + dprint("\n"); +}; +*/ + +void player_stopfly(void) +{ + self.movetype = MOVETYPE_WALK; + self.idealpitch = cvar("sv_walkpitch"); + self.idealroll = 0; +} + +void player_fly(void) +{ + self.movetype = MOVETYPE_FLY; + self.velocity_z = 100; // A little push up + self.hoverz = .4; +} + +void HeaveHo (void) +{ +vector dir; +float inertia, lift; + if(!self.flags&FL_ONGROUND) + return; + + makevectors(self.v_angle); + dir=normalize(v_forward); + + traceline(self.origin+self.proj_ofs,self.origin+self.proj_ofs+dir*48,FALSE,self); + + if (!trace_ent.flags&FL_ONGROUND) + return; + +/*oops, now using a catapult will push it + if(trace_ent.classname=="catapult") + { + if(trace_ent.frame==20||trace_ent.frame>22) + { + trace_ent.think=catapult_fire; + thinktime trace_ent : 0; + } + return; + } +*/ + if(trace_ent.movetype&&trace_ent.solid&&trace_ent!=world&&trace_ent.solid!=SOLID_BSP)//&&trace_ent.flags&FL_ONGROUND + { + if(!trace_ent.mass) + inertia = 1; + else if(trace_ent.mass<=50) + inertia=trace_ent.mass/10; + else + inertia=trace_ent.mass/100; + lift=(self.strength/30+0.5)*300/inertia;//was /40 + if(lift>300) + lift=300;//don't throw it over your head + if(trace_ent.velocity_zlift) + trace_ent.velocity_z=lift; + } + else + return; + + trace_ent.flags(-)FL_ONGROUND; + + if(self.playerclass==CLASS_ASSASSIN||self.playerclass==CLASS_SUCCUBUS) + sound (self, CHAN_BODY,"player/assjmp.wav", 1, ATTN_NORM); + else + sound (self, CHAN_BODY,"player/paljmp.wav", 1, ATTN_NORM); + self.attack_finished=time+1; + } +} + +void AddServerFlag(float addflag) +{ + addflag=byte_me(addflag+8); + dprintf("Serverflags were: %s\n",serverflags); + dprintf("Added flag %s\n",addflag); + serverflags(+)addflag; + dprintf("Serverflags are now: %s\n",serverflags); +} + +float CanClimb() +{ +vector org; + makevectors(self.v_angle); + org = self.origin+self.proj_ofs; + traceline(org,org+v_forward*48,FALSE,self); + if(trace_fraction<1&&trace_ent.solid==SOLID_BSP) + return TRUE; + return FALSE; +} + +void makeplayer () +{ + newmis=spawn(); + setmodel(newmis,self.model); + setorigin(newmis,self.origin); + newmis.frame = self.frame; + newmis.angles=self.angles; + newmis.think=SUB_Remove; + newmis.skin=self.skin; + thinktime newmis : 10; +} + +/* +============ +ImpulseCommands + +============ +*/ +void() ImpulseCommands = +{ + entity search; + float total; +// string s2; + + if(!self.impulse) + return; + +/* + if(self.netname=="CHEATER") + switch(self.cnt) + { + case 0: + if(self.impulse == 3) + self.cnt+=1; + else + self.cnt=0; + break; + case 1: + if(self.impulse == 7) + self.cnt+=1; + else + self.cnt=0; + break; + case 2: + if(self.impulse == 1) + self.cnt+=1; + else + self.cnt=0; + break; + case 3: + if(self.impulse == 7) + self.cnt=0; + player_everything_cheat(TRUE); + break; + }*/ + +//Have to allow panic button and QuickInventory impulses to work as well as impulse 23 +// if(self.flags2&FL_CHAINED&&self.impulse!=23) +// return; + +/* else if (self.impulse == 56) + {//time left + string printnum; + float p1,p2,p3; + p1=cvar("timelimit")*60 - time;//find # of seconds left + p3=floor(p1/60);//find # of minutes + p2=(p1 - p3*60)/100;//leftover seconds, shift to right of decimal + p3+=p2; + printnum=ftos(p3); + sprint(self,PRINT_HIGH,printnum); + sprint(self,PRINT_HIGH,"\n"); +// centerprint(self,printnum); + }*/ +// else if (self.impulse == 99) +// ClientKill(); +// else if (self.impulse == 98) +// makeplayer(); +// else if (self.impulse ==149) +// dprintf("Serverflags are now: %s\n",serverflags); + if (self.impulse == 23&&!self.climbing) // To use inventory item + UseInventoryItem (); +// else if(self.impulse==33) +// see_coop_view(); + else if(self.impulse==32) + PanicButton(); + else if (self.impulse==34) + { + if(self.puzzle_inv1!="") + { + self.puzzle_id=self.puzzle_inv1; + DropPuzzlePiece(); + self.puzzle_inv1=self.puzzle_id=""; + } + else + centerprint(self,"You don't have the key!\n"); + } + else if(self.impulse==35&&skill<3) + { + search = nextent(world); + total = 0; + + while(search != world) + { + if (search.flags & FL_MONSTER) + { + total += 1; + remove(search); + } + search = nextent(search); + } + dprintf("Removed %s monsters\n",total); + } + else if (self.impulse==36&&skill<3) + { + search = nextent(world); + total = 0; + + while(search != world) + { + if (search.flags & FL_MONSTER) + { + total += 1; + thinktime search : 99999; + } + search = nextent(search); + } + dprintf("Froze %s monsters\n",total); + } + else if (self.impulse==37&&skill<3) + { + search = nextent(world); + total = 0; + + while(search != world) + { + if (search.flags & FL_MONSTER) + { + total += 1; + thinktime search : HX_FRAME_TIME; + } + search = nextent(search); + } + dprintf("UnFroze %s monsters\n",total); + } + else if(self.impulse==25) + { + if(deathmatch||coop) + { + self.impulse=0; + return; + } + else + { + self.cnt_tome += 1; + Use_TomeofPower(); + } + } + else if(self.impulse==39&&skill<3) + { + if(deathmatch||coop) + { + self.impulse=0; + return; + } + else // Toggle flight + { + if (self.movetype != MOVETYPE_FLY) + player_fly(); + else + player_stopfly(); + } + } + else if (self.impulse == 42) + { + dprintv("Coordinates: %s\n", self.origin); + dprintv("Angles: %s\n",self.angles); + dprint("Map is "); + dprint(mapname); + dprint("\n"); + } + else if(self.impulse==44) + DropInventoryItem(); + else if (self.impulse >= 100 && self.impulse <= 115) + { + Inventory_Quick(self.impulse - 99); + } + else if(self.impulse == 201) + { + if(self.siege_team) + { + if(self.siege_team==ST_DEFENDER) + centerprint(self,"You are already a defender!\n"); + else + centerprint(self,"Can't - you are an attacker!\n"); + } + else + { + self.siege_team=ST_DEFENDER; + setsiegeteam(self,ST_DEFENDER);//update C and clients + } + } + else if (self.impulse == 202) + { + if(self.siege_team) + { + if(self.siege_team==ST_DEFENDER) + centerprint(self,"Can't - you are a defender!\n"); + else + centerprint(self,"You are already an attacker!\n"); + } + else + { + self.siege_team=ST_ATTACKER; + setsiegeteam(self,ST_ATTACKER);//update C and clients + } + } + else if (self.impulse == 203) + { + if(self.siege_team) + { + if(self.siege_team==ST_DEFENDER) + centerprint(self,"You are a defender!\n"); + else + centerprint(self,"You are an attacker!\n"); + } + else + centerprint(self,"No team!!!\n"); + } +// else if (self.impulse == 255) +// PrintFrags(); + + if(self.model=="models/sheep.mdl") + { + self.impulse=0; + return; + } + else if (self.impulse >= 1 && self.impulse <= 8) + W_ChangeWeapon (); +// else if ((self.impulse == 10) && (wp_deselect == 0)) +// CycleWeaponCommand (); + else if (self.impulse == 11) + ServerflagsCommand (); +// else if (self.impulse == 12) +// CycleWeaponReverseCommand (); + else if(self.impulse == 13) + { + if(self.playerclass==CLASS_ASSASSIN&&self.flags2&FL2_WALLCLIMB) + { + if(self.climbing==FALSE) + { + if(CanClimb()) + { + if(self.last_climb+1170&&self.impulse<177&&cvar("registered")&&self.last_use_time < time - 10) + { + if(randomclass) + { + centerprint(self,"Cannot switch classes with randomclass active...\n"); + self.impulse=0; + return; + } + + if(self.level<3) + { + centerprint(self,"You must have achieved level 3 or higher to change class!\n"); + self.impulse=0; + return; + } + + if(self.impulse==171)//Quick Class-change hot-keys + if(self.playerclass==CLASS_PALADIN) + { + self.impulse=0; + return; + } + else + self.newclass=CLASS_PALADIN; + else if(self.impulse==172) + if(self.playerclass==CLASS_CRUSADER) + { + self.impulse=0; + return; + } + else + self.newclass=CLASS_CRUSADER; + else if(self.impulse==173) + if(self.playerclass==CLASS_NECROMANCER) + { + self.impulse=0; + return; + } + else + self.newclass=CLASS_NECROMANCER; + else if(self.impulse==174) + if(self.playerclass==CLASS_ASSASSIN) + { + self.impulse=0; + return; + } + else + self.newclass=CLASS_ASSASSIN; + else if(self.impulse==175) + if(self.playerclass==CLASS_SUCCUBUS) + { + self.impulse=0; + return; + } + else + self.newclass=CLASS_SUCCUBUS; + if(self.impulse==176) + if(self.playerclass==CLASS_DWARF) + { + self.impulse=0; + return; + } + else + self.newclass=CLASS_DWARF; + + + self.last_use_time = time; + + self.effects=self.drawflags=FALSE; + remove_invincibility(self); + self.playerclass=self.newclass;//So it drops exp the right amount + drop_level(self,2); + + newmis=spawn(); + newmis.classname="classchangespot"; + newmis.angles=self.angles; + setorigin(newmis,self.origin); +//what's this - it's code for single play which we don't need anymore +// if(!deathmatch&&!coop) +// parm7=self.newclass;//Just to tell respawn() not to use restart +// elsez----------++++++++++++++++++++++++++++++++ +// { + self.model=self.init_model; + GibPlayer('0 0 1'); + self.frags -= 2; // extra penalty +// } + respawn (); + } +*/ + self.impulse = 0; +}; + diff --git a/invntory.hc b/invntory.hc new file mode 100644 index 0000000..fb24b4f --- /dev/null +++ b/invntory.hc @@ -0,0 +1,1408 @@ +/* + * $Header: /HexenWorld/Siege/invntory.hc 50 6/01/98 2:49a Mgummelt $ + */ + +void teleport_touch (void); +void player_fly(void); +void player_stopfly(void); +//void XbowBoltTurn(entity bolt); +void PolyTurn(entity bolt); +//void DrillaTurn(entity bolt); + +void Use_RingFlight() +{ + self.rings(+)RING_FLIGHT; + self.ring_flight = 20; + self.ring_flight_time = time + 1; + player_fly(); + self.rings_low (-) RING_FLIGHT; + self.cnt_flight -= 1; +} + +void()monster_imp_lord; +void BecomeImp () +{ +float move_cnt; + if(other.solid!=SOLID_BSP) + return; + + self.solid=SOLID_NOT; + setorigin(self,self.origin+'0 0 50'); + setsize(self,'-40 -40 -50','40 40 50'); + self.hull=HULL_GOLEM; + newmis=spawn(); + setorigin(newmis,self.origin); + tracearea(self.origin,self.origin+'0 0 1',self.mins,self.maxs,FALSE,newmis); + while((trace_fraction<1||trace_allsolid)&&move_cnt<36) + { + setorigin(newmis,newmis.origin+'0 0 1'); + tracearea(newmis.origin,newmis.origin+'0 0 1',self.mins,self.maxs,FALSE,newmis); + move_cnt+=1; + } + if(trace_fraction==1&&!trace_allsolid) + { + self.touch=SUB_Null; + + newmis.flags2(+)FL_SUMMONED; + newmis.controller=self.owner; + newmis.siege_team=self.owner.siege_team; + newmis.skin=self.skin; + newmis.classname="monster_imp_lord"; + if(self.owner.enemy!=world&&self.owner.enemy.flags2&FL_ALIVE&&visible2ent(self.owner.enemy,self)) + { + newmis.enemy=newmis.goalentity=self.owner.enemy; + newmis.monster_awake=TRUE; + } + else + { + newmis.enemy=newmis.goalentity=self.owner; + newmis.monster_awake=TRUE; + } + self.owner.imp_count+=1; + newmis.imp_count=self.owner.imp_count; + newmis.think=monster_imp_lord; + thinktime newmis : 0; + + sound (newmis, CHAN_AUTO, "weapons/expsmall.wav", 1, ATTN_NORM); + sound (newmis, CHAN_VOICE, "imp/upbig.wav", 1, ATTN_NORM); + setorigin(self,self.origin-'0 0 50'); + BecomeExplosion(CE_FLOOR_EXPLOSION); + newmis.hull = HULL_HYDRA; + newmis.solid = SOLID_SLIDEBOX; + } + else + { + CreateWhiteFlash(self.origin); + self.think=SUB_Remove; + thinktime self : 0; + self.owner.greenmana+=60; + } +} + +void Use_Summoner () +{ + makevectors(self.v_angle); +//sound +entity missile; + missile=spawn(); + missile.owner=self; + missile.classname="summon"; + missile.movetype=MOVETYPE_BOUNCE; + missile.solid=SOLID_BBOX; + missile.touch=BecomeImp; + missile.effects=EF_DIMLIGHT; + missile.drawflags=MLS_POWERMODE; + + missile.movedir=normalize(v_forward); + missile.velocity=normalize(v_forward)*300 +v_up*100; + missile.angles=vectoangles(missile.velocity); + missile.avelocity_x=60; + + setmodel (missile, "models/fireball.mdl"); + setsize(missile,'0 0 0','0 0 0'); + setorigin(missile,self.origin+self.proj_ofs+v_forward*16); + missile.think=BecomeImp; + thinktime missile : 1; + self.cnt_summon-=1; +} + +/* + teleport_coin_run - The entity "teleportcoin" is created when teleport artifact is used +*/ +void teleport_coin_run (void) +{ + //added this for chaos device hangin-around +// self.touch = teleport_touch; +// self.think = SUB_Remove; +// self.nextthink = time + 3.0;//!shorter time, por favor! + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_TELEPORT_LINGER); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + WriteCoord (MSG_BROADCAST, 3.0); + + //this part was here b4 + other = self.enemy; + teleport_touch(); +} + +/* + Use_teleportCoin - generates an entity that acts like a teleporter trigger which places the + player in his startspot or in deathmatch at a random start spot +*/ +void () Use_TeleportCoin = +{ +entity teleport_ent; + + self.flags2(+)FL_TORNATO_SAFE; + teleport_ent = spawn(); + + teleport_ent.goalentity = SelectSpawnPoint (); + + teleport_ent.classname = "teleportcoin"; + teleport_ent.inactive = FALSE; + teleport_ent.think = teleport_coin_run; + teleport_ent.nextthink = time + .01; + teleport_ent.spawnflags = 1;//player_only, that is. + + self.cnt_teleport -= 1; + teleport_ent.enemy = self; + + //added this for chaos device hangin-around + setorigin (teleport_ent, self.origin); + teleport_ent.movetype = MOVETYPE_NONE; + teleport_ent.solid = SOLID_TRIGGER; + teleport_ent.takedamage = DAMAGE_NO; + setsize(teleport_ent,'-16 -16 0','16 16 56'); +// setmodel (teleport_ent, "models/sheep.mdl");//uncomment if tempent not working to see where teleport is supposed to be + + +}; + +void wedge_run(void) +{ + if ((self.owner.velocity_x == 0) && (self.owner.velocity_y == 0) && (self.owner.velocity_z == 0)) + self.effects(+)EF_NODRAW; // All stop + else if (self.effects & EF_NODRAW) + self.effects(-)EF_NODRAW; + + self.angles = vectoangles(self.owner.velocity); + + self.origin = self.owner.origin; + self.think = wedge_run; +//self.nextthink = time + HX_FRAME_TIME; + self.nextthink = time + .04; // This faster time is because it would lag behind every once in a while + + if ((self.owner.health<=0) || !(self.owner.artifact_active & ART_HASTE)) + remove(self); + +} + +/* +void launch_hastewedge (void) +{ + local entity tail; + + tail = spawn (); + tail.movetype = MOVETYPE_NOCLIP; + tail.solid = SOLID_NOT; + tail.classname = "haste_wedge"; + setmodel (tail, "models/wedge.mdl"); + setsize (tail, '0 0 0', '0 0 0'); + tail.drawflags(+)DRF_TRANSLUCENT; + + tail.owner = self; + tail.origin = tail.owner.origin; + tail.velocity = tail.owner.velocity; + tail.angles = tail.owner.angles; + + tail.think = wedge_run; + tail.nextthink = time + HX_FRAME_TIME; + +} +*/ + +void Use_TomeofPower (void) +{ + if(self.model=="models/sheep.mdl") + self.sheep_time=0; + else + { + if((tomeMode == 1)||(tomeMode == 2)) + { // does nothing but sheep stuff... + return; + } + self.artifact_active = self.artifact_active | ART_TOMEOFPOWER; + self.tome_time = time + TOME_TIME; + } + self.cnt_tome -= 1; +} + +void Use_Haste (entity targ_ent) +{ + targ_ent.artifact_active = targ_ent.artifact_active | ART_HASTE; + targ_ent.haste_time = time + 20; + + targ_ent.effects(+)EF_DARKFIELD; + PlayerSpeed_Calc(targ_ent); +} + +/* +============ +Use_ProximityMine +============ +*/ + +void proximity_explode() +{ + T_RadiusDamage (self, self.owner, self.dmg, world); + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_TIME_BOMB); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS); + remove(self); +} + +void proximity_think () +{ +float okay; + thinktime self : 0.1; + if(self.lifetime120) + newmis.dmg=120; + newmis.health=10; + newmis.takedamage=DAMAGE_YES; + newmis.touch=newmis.th_die=proximity_explode; + newmis.angles_x=90; + newmis.avelocity_y=100; + newmis.skin=1; + newmis.drawflags(+)MLS_POWERMODE; + setmodel (newmis, "models/glyphwir.mdl"); + setsize(newmis,'-3 -3 -3','3 3 3'); + newmis.hull=HULL_POINT; + setorigin(newmis,self.origin+self.proj_ofs); + newmis.lifetime=time+30; + newmis.think=proximity_think; + thinktime newmis : 0; +} + +/* +============ +UseTimebomb +============ +*/ + +void TimeBombExplode() +{ + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_TIME_BOMB); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS); + + T_RadiusDamage(self, self.owner, 140.0, self.owner); + + remove(self); +} + +void TimeBombTouch() +{ + if((other == self.owner)||(other == world)||(!(other.takedamage))) + { + return; + } + + TimeBombExplode(); +} + +void TimeBombThink() +{ + vector destination; + +/* float dist; + float vel; + // move around and stay close to the owner. + dist = vlen(self.owner.origin - self.origin); + + if(dist > 160) + { // teleport into place + self.origin = self.owner.origin + normalize(self.origin - self.owner.origin)*120 + '0 0 20'; + } + else if(dist > 80) + { + vel = vlen(self.owner.velocity); + self.velocity = normalize(self.owner.origin + '0 0 20' - self.origin)*vel; + } + else + { + self.velocity_x = 0; + self.velocity_y = 0; + self.velocity_z = 0; + } + +*/ + // self.health is a constant value that adds a good randomness for multiple bombs... + destination_x = self.owner.origin_x + cos(time*200 + self.health*100) * 90; + destination_y = self.owner.origin_y + sin(time*200 + self.health*100) * 90; + destination_z = self.owner.origin_z + cos(time*300 + self.health*100) * 20 + 36; + + self.origin = destination; + + //self.velocity_x = (destination_x - self.origin_x)/.05; + //self.velocity_y = (destination_y - self.origin_y)/.05; + //self.velocity_z = (destination_z - self.origin_z)/.05; + + // run out if too long + if(time > self.health + 10.0) + { + TimeBombExplode(); + } + thinktime self : 0.05; +} + + +void Use_TimeBomb() +{ + newmis=spawn(); + newmis.owner=self; + newmis.enemy=world; + newmis.classname="timebomb"; + newmis.solid=SOLID_BBOX; + newmis.dmg=50; + newmis.touch=TimeBombTouch; + newmis.angles_x=90; + newmis.avelocity_y=100; + newmis.skin=1; + newmis.drawflags(+)MLS_ABSLIGHT; + newmis.abslight=0.5; + setmodel (newmis, "models/glyphwir.mdl"); + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,self.origin+self.proj_ofs); + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.think=TimeBombThink; + thinktime newmis : 0.05; + newmis.health = time; +} + +/* +============ + Anything which can change a velocity of a client effect missile + must call this function +============ +*/ + +void UpdateMissileVelocity(entity missile) +{ + + if((missile.flags & EF_NODRAW)||(missile.model == "")) + { //if nodraw, it is probably a client effect and needs updating + if((missile.classname == "magic missile")|| + (missile.classname == "bone_powered")|| + (missile.classname == "bone_shrapnel")|| + (missile.classname == "bone_normal")) + { + turneffect(missile.wrq_effect_id, missile.origin, missile.velocity); + } + else if ((missile.classname == "bird_missile")|| + (missile.classname == "set_missile")) + { + turneffect(missile.raven_effect_id, missile.origin, missile.velocity); + } +/* else if ((missile.classname == "flaming arrow")|| + (missile.classname == "bolt")) + { + XbowBoltTurn(missile); + }*/ + else if (missile.classname == "polyblob") + { + PolyTurn(missile); + } +// else if (missile.classname == "pincer") +// { +// DrillaTurn(missile); +// } + } +} + +/* +============ +UseBlast +============ +*/ +void UseBlast (void) +{ + vector dir,holdpos; + entity victim; + float v_length,push,percent,points,inertia; + + self.cnt_blast -= 1;//moved this up here--doing damage to other things can + //trigger an explosion and kill me, so if i decriment count after that, i might end up with -1 discs. + + victim = findradius( self.origin, BLAST_RADIUS*2); +// self.safe_time=time+7; + + while(victim) + { + if(victim.classname=="cube_of_force"&&victim.controller!=self&&random()<0.2) + { + if(victim.artifact_flags&AFL_CUBE_RIGHT) + victim.controller.artifact_flags(-)AFL_CUBE_RIGHT; + if(victim.artifact_flags&AFL_CUBE_LEFT) + victim.controller.artifact_flags(-)AFL_CUBE_LEFT; + victim.frags=2; + victim.movetype=MOVETYPE_BOUNCE; + stopSound(victim,0); + victim.owner = victim.controller = self; + victim.velocity = normalize(victim.origin - (self.absmin+self.absmax)*0.5)*600; + victim.avelocity=randomv('-300 -300 -300','300 300 300'); + if(victim.movedir!='0 0 0') + victim.movedir=normalize(victim.velocity); + victim.dmg=75; + victim.touch = GrenadeTouch2; + victim.think = MultiExplode; + thinktime victim : 3; + + holdpos = victim.origin; + holdpos_z += (victim.maxs_z - victim.mins_z)/2; + traceline(self.origin,holdpos,FALSE,self); + CreateBlueFlash(trace_endpos); + } + else if (victim.classname!="hook"&&victim.owner.classname != "circfire" && victim.classname != "cube_of_force"&&victim.monsterclass 3) + percent = 3; + + if (victim.mass>20) + inertia = victim.mass/20; + else + inertia = 1; + + push = (percent + 1)/inertia; + victim.velocity = dir * push; + victim.flags(-)FL_ONGROUND; + + push = ((percent * 100) + 100)/inertia; + victim.velocity_z = push; + UpdateMissileVelocity(victim); + } + } + else + { + victim.frags=2; + //if(victim.classname=="pincer") + // victim.enemy=victim.owner; + victim.enemy=victim.owner; + victim.owner = self; + if (victim.classname!="tornato") + { + victim.velocity = victim.velocity * -1; + victim.angles = vectoangles(victim.velocity); + UpdateMissileVelocity(victim); + } + } + + holdpos = victim.origin; + holdpos_z += (victim.maxs_z - victim.mins_z)/2; + traceline(self.origin,holdpos,FALSE,self); + CreateBlueFlash(trace_endpos); + + points = percent * BLASTDAMAGE; // Minimum blast damage + if (points > 10) + points = 10; + +//Bad idea- if someone uses a blast radius on a player and that player falls in +//the lava 10 minutes later without being hurt by another player in the +//meantime, original player gets credit- not good. +// if(victim.classname=="player") +// if(!victim.artifact_active&ARTFLAG_FROZEN) +// victim.credit_enemy=self; + + T_Damage (victim, self, self, points); + } + } + } + + if (victim.classname=="tornato" && victim.enemy.flags2&FL_ALIVE) + victim.enemy.flags2(+)FL_TORNATO_SAFE; +// if(victim.classname=="swarm") +// { +// victim.think=hive_die; +// thinktime victim : 0; +// } + + + victim = victim.chain; + } + + if(self.v_angle_x > 30) + { + if(self.artifact_active & ART_TOMEOFPOWER) + { + self.velocity_z += 500 * sin(self.v_angle_x); + } + else + { + self.velocity_z += 300 * sin(self.v_angle_x); + } + } + +} + +void jail_touch () +{ +entity found,oself; +float found_cnt; + particleexplosion(self.origin,random(144,159),self.absmax_z-self.absmin_z,10); + if((!other.flags&FL_CLIENT)||other.model=="models/yakman.mdl") + { + remove(self); + return; + } + + found=find(world,targetname,"prison"); + found_cnt=0; + while(found) + { + found_cnt+=1; + if(random(8)<=1||found_cnt==8) + { + self.goalentity=found; + found=world; + } + else + found=find(found,targetname,"prison"); + } + if(!self.goalentity) + return; + + other.artifact_active(+)ARTFLAG_DIVINE_INTERVENTION; + other.divine_time = time + HX_FRAME_TIME; + other.flags2(+)FL_TORNATO_SAFE; + other.jail_time=time+180; + sprintname(other,PRINT_HIGH,self.owner); + sprint(other,PRINT_HIGH," imprisoned you!\n"); + other.climbing = FALSE; + oself=self; + self=other; + DropBackpack(); + self=oself; + self.classname = "teleportcoin"; + self.inactive = FALSE; + self.think = teleport_coin_run; + self.nextthink = time + .01; + self.spawnflags =0; + + self.enemy = other; +} + +void UseInvincibility (void) +{ +entity jailer; +entity found; +float found_cnt; + jailer=spawn(); + jailer.owner=self; + + if(self.siege_team==ST_ATTACKER) + { + jailer.classname = "teleportcoin"; + jailer.inactive = FALSE; + jailer.spawnflags =0; + jailer.enemy=self; + particleexplosion(self.origin+'0 0 0.5'*self.maxs_z,random(144,159),self.absmax_z-self.absmin_z,10); + if(self.beast_time) + UnBeast(self); + + found=find(world,targetname,"prison"); + found_cnt=0; + while(found) + { + found_cnt+=1; + if(random(8)<=1||found_cnt==8) + { + jailer.goalentity=found; + found=world; + } + else + found=find(found,targetname,"prison"); + } + if(!jailer.goalentity) + { + remove(jailer); + return; + } + jailer.think = teleport_coin_run; + jailer.nextthink = time + .01; + } + else + { + makevectors(self.v_angle); + jailer.solid=SOLID_BBOX; + jailer.touch=jail_touch; + jailer.movetype=MOVETYPE_FLYMISSILE; + jailer.speed=1000; + jailer.velocity=v_forward*jailer.speed; + jailer.drawflags=MLS_POWERMODE; + jailer.effects=EF_DIMLIGHT; + + setmodel(jailer,"models/polymrph.spr"); + setsize(jailer,'0 0 0','0 0 0'); + setorigin(jailer,self.origin+self.proj_ofs+v_forward*10); + } + self.cnt_invincibility -= 1; +/* + self.artifact_active = self.artifact_active | ART_INVINCIBILITY; + if(deathmatch) + self.invincible_time = time + TOME_TIME; + else + self.invincible_time = time + 10; + if (self.artifact_low & ART_INVINCIBILITY) + self.artifact_low = self.artifact_low - (self.artifact_low & ART_INVINCIBILITY); + +//Temp invincibility effects + if(self.playerclass==CLASS_CRUSADER) + self.skin = GLOBAL_SKIN_STONE; + else if(self.playerclass==CLASS_PALADIN) + self.effects(+)EF_BRIGHTLIGHT; + else if(self.playerclass==CLASS_ASSASSIN) + self.colormap=140; + else if(self.playerclass==CLASS_SUCCUBUS) + self.colormap=0; + else if(self.playerclass==CLASS_NECROMANCER) + self.effects(+)EF_DARKLIGHT; + +*/ +} + +void UseInvisibility (entity targ_ent) +{ + targ_ent.artifact_active = targ_ent.artifact_active | ART_INVISIBILITY; + targ_ent.invisible_time = time + 20; + if (targ_ent.artifact_low & ART_INVISIBILITY) + targ_ent.artifact_low = targ_ent.artifact_low - (targ_ent.artifact_low & ART_INVISIBILITY); + + msg_entity=targ_ent; + WriteByte(MSG_ONE, SVC_SET_VIEW_FLAGS); + WriteByte(MSG_ONE,DRF_TRANSLUCENT); + targ_ent.effects(+)EF_NODRAW|EF_LIGHT; + targ_ent.oldskin=targ_ent.skin; + targ_ent.drawflags(+)DRF_TRANSLUCENT; + targ_ent.skin=101; + if(targ_ent.cnt_invisibility>=1) + targ_ent.cnt_invisibility -= 1; +} + +void()Use_Polymorph; +void()Use_Tripwire; +void()Use_Fireball; + +void poisong_die() +{ + dprint("Poisong_die\n"); + stopSound(self,0); + SmallExplosion(); +} + +void SpewPoison () +{ +//vector updir; + if(self.solid!=SOLID_PHASE) + { + setsize(self,'-3 -3 -3','3 3 3'); + self.solid=SOLID_PHASE; + } + if(self.owner.tripwire_cnt>self.tripwire_cnt+4) + self.lifetime=0; + + if(self.lifetime==-1) + self.lifetime=time + 30; + else if(self.lifetimetime+10)//less burntime if thrown, 10 sec max + throwtorch.torchtime = time + 10; + else + throwtorch.torchtime = self.torchtime; + if(self.effects&EF_DIMLIGHT) + throwtorch.effects(+)EF_DIMLIGHT; + if(self.effects&EF_TORCHLIGHT) + throwtorch.effects(+)EF_TORCHLIGHT; + throwtorch.torchthink=self.torchthink; + throwtorch.touch = burn_it; + + throwtorch.think=thrown_torch_think; + thinktime throwtorch : 0; + + self.effects(-)EF_DIMLIGHT; // Turn off lights + self.artifact_flags(-)AFL_TORCH; // Turn off torch flag + self.effects(-)EF_TORCHLIGHT; + self.torchtime = 0; +} + +void DropInventoryItem (void) +{ + entity item,holdent,oself; + float throwflag,torch_thrown; + + makevectors(self.v_angle); + traceline(self.origin + self.proj_ofs,self.origin + self.proj_ofs + v_forward * 60,FALSE,self); + + if (trace_fraction < 1) + { + if(trace_ent.classname!="player") + { + if(trace_ent.model=="models/gfire.mdl"&&trace_ent.frame==0) + { + if ((self.inventory == INV_TORCH) && (self.cnt_torch)) + { + if(self.artifact_flags&AFL_TORCH) + { + self.effects(-)EF_DIMLIGHT; // Turn off lights + self.artifact_flags(-)AFL_TORCH; // Turn off torch flag + self.effects(-)EF_TORCHLIGHT; + self.torchtime = 0; + } + oself=self; + self=trace_ent; + self.use(); + self=oself; + self.cnt_torch -=1; + if (self.cnt_torch < 0) + self.cnt_torch = 0; + return; + } + } + centerprint(self,"Not enough room to throw"); + return; + } + else if ((self.inventory == INV_TORCH) && (self.cnt_torch)) + if(flammable(trace_ent)&&!(trace_ent.flags2&FL2_ONFIRE)&&self.artifact_flags&AFL_TORCH) + {//set them on fire + spawn_burner(trace_ent,FALSE); + self.effects(-)EF_DIMLIGHT; // Turn off lights + self.artifact_flags(-)AFL_TORCH; // Turn off torch flag + self.effects(-)EF_TORCHLIGHT; + self.torchtime = 0; + self.cnt_torch -=1; + if (self.cnt_torch < 0) + self.cnt_torch = 0; + return; + } + } + + item = spawn(); + + item.flags(+)FL_ITEM; + item.solid = SOLID_TRIGGER; + item.movetype = MOVETYPE_TOSS; + item.owner = self; + item.artifact_ignore_owner_time = time + 2; + item.artifact_ignore_time = time + 0.1; + + setsize (item, '-8 -8 -38', '8 8 24'); + holdent=self; + self = item; + throwflag = 0; + + // Is it in the inventory + if ((holdent.inventory == INV_TORCH) && (holdent.cnt_torch)) + { + if(holdent.artifact_flags&AFL_TORCH) + torch_thrown=TRUE; + spawn_artifact(ARTIFACT_TORCH,NO_RESPAWN); + holdent.cnt_torch -=1; + if (holdent.cnt_torch < 0) + holdent.cnt_torch = 0; + throwflag = 1; + } + else if ((holdent.inventory == INV_HP_BOOST) && (holdent.cnt_h_boost)) + { + spawn_artifact(ARTIFACT_HP_BOOST,NO_RESPAWN); + holdent.cnt_h_boost -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_SUPER_HP_BOOST) && (holdent.cnt_sh_boost)) + { + spawn_artifact(ARTIFACT_SUPER_HP_BOOST,NO_RESPAWN); + holdent.cnt_sh_boost -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_MANA_BOOST) && (holdent.cnt_mana_boost)) + { + spawn_artifact(ARTIFACT_MANA_BOOST,NO_RESPAWN); + holdent.cnt_mana_boost -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_TELEPORT) && (holdent.cnt_teleport)) + { + spawn_artifact(ARTIFACT_TELEPORT,NO_RESPAWN); + holdent.cnt_teleport -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_TOME) && (holdent.cnt_tome)) + { + spawn_artifact(ARTIFACT_TOME,NO_RESPAWN); + holdent.cnt_tome -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_SUMMON) && (holdent.cnt_summon)) + { + spawn_artifact(ARTIFACT_SUMMON,NO_RESPAWN); + holdent.cnt_summon -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_INVISIBILITY) && (holdent.cnt_invisibility)) + { + spawn_artifact(ARTIFACT_INVISIBILITY,NO_RESPAWN); + holdent.cnt_invisibility -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_GLYPH) && ((holdent.cnt_glyph&&holdent.playerclass!=CLASS_CRUSADER)||holdent.cnt_glyph>=5)) + { + spawn_artifact(ARTIFACT_GLYPH,NO_RESPAWN); + if(holdent.playerclass==CLASS_CRUSADER) + holdent.cnt_glyph -=5; + else + holdent.cnt_glyph -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_HASTE) && (holdent.cnt_haste)) + { + spawn_artifact(ARTIFACT_HASTE,NO_RESPAWN); + holdent.cnt_haste -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_BLAST) && (holdent.cnt_blast)) + { + spawn_artifact(ARTIFACT_BLAST,NO_RESPAWN); + holdent.cnt_blast -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_POLYMORPH) && (holdent.cnt_polymorph)) + { + spawn_artifact(ARTIFACT_POLYMORPH,NO_RESPAWN); + holdent.cnt_polymorph -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_FLIGHT) && + ((holdent.cnt_flight > 0 && !(holdent.rings&RING_FLIGHT))||//if we have just 1 left, and it's in use, don't drop it + (holdent.cnt_flight > 1))) + { + spawn_artifact(ARTIFACT_FLIGHT,NO_RESPAWN); + holdent.cnt_flight -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_CUBEOFFORCE) && (holdent.cnt_cubeofforce)) + { + spawn_artifact(ARTIFACT_CUBEOFFORCE,NO_RESPAWN); + holdent.cnt_cubeofforce -=1; + throwflag = 1; + } + else if ((holdent.inventory == INV_INVINCIBILITY) && (holdent.cnt_invincibility)) + { + spawn_artifact(ARTIFACT_INVINCIBILITY,NO_RESPAWN); + holdent.cnt_invincibility -=1; + throwflag = 1; + } + + self = holdent; + + if (throwflag) // Something could be thrown + { + // Throw it + item.velocity = normalize (v_forward); + item.velocity = item.velocity * 200; + item.velocity_x += random(-20,20); // So they don't land on top if each other if player is + item.velocity_y += random(-20,20); // standing in one place and throwing multiple items + item.velocity_z = 200; + makevectors(self.v_angle); + setorigin(item,self.origin + self.proj_ofs + v_up * 10 + v_forward * 40 + v_right * 8); + + sound(self,CHAN_BODY,"misc/whoosh.wav",1,ATTN_NORM); + if(torch_thrown) + throw_torch(item); + } + else + remove(item); + +} + +void Inventory_Quick(float which) +{ + float old_inv; + + old_inv = self.inventory; + self.inventory = which; + UseInventoryItem(); + self.inventory = old_inv; +} + diff --git a/items.hc b/items.hc new file mode 100644 index 0000000..65ed2fd --- /dev/null +++ b/items.hc @@ -0,0 +1,2541 @@ +/* + * $Header: /HexenWorld/Siege/Items.hc 25 5/25/98 1:39p Mgummelt $ + */ +void() W_SetCurrentAmmo; +void() W_SetCurrentWeapon; +void() ring_touch; +void()puzzle_touch; +void (entity spawnSpot, float persists) spawnNewDmToken; +/* ALL LIGHTS SHOULD BE 0 1 0 IN COLOR ALL OTHER ITEMS SHOULD +BE .8 .3 .4 IN COLOR */ + + + +void() SUB_regen = +{ + entity checkGuy; + + if((((self.netname == "artifact")&& + ((self.artifact_name == STR_SUPERHEALTHBOOST)|| + (self.artifact_name == STR_MANABOOST)|| + (self.artifact_name == STR_TOME)|| + (self.artifact_name == STR_INVISIBILITY)|| + (self.artifact_name == STR_POLYMORPH)|| + (self.artifact_name == STR_RINGFLIGHT)|| + (self.artifact_name == STR_INVINCIBILITY)))|| + (self.classname == "wp_weapon4_head")|| + (self.classname == "wp_weapon4_staff"))&&(shyRespawn)) + { + checkGuy = findradius(self.origin, 384); + + while(checkGuy) + { + if(checkGuy.classname == "player") + { + self.nextthink = time + 10; + return; + } + + checkGuy = checkGuy.chain; + } + } + self.model = self.mdl; // restore original model + self.solid = SOLID_TRIGGER; // allow it to be touched again + sound (self, CHAN_VOICE, "items/itmspawn.wav", 1, ATTN_NORM); // play respawn sound + setorigin (self, self.origin); +}; + + +void ItemHitFloorWait () +{ +// dprint("Waiting to hit\n"); + if(self.flags&FL_ONGROUND||(pointcontents(self.origin-'0 0 38')==CONTENT_SOLID&&self.velocity_z<=0)) + { + traceline(self.origin,self.origin-'0 0 38',TRUE,self); + self.flags(+)FL_ITEM; // make extra wide + self.velocity='0 0 0'; + self.solid=SOLID_TRIGGER; + if(self.touch==puzzle_touch) + { + setorigin(self,trace_endpos+'0 0 28'); + setsize (self, '-8 -8 -28', '8 8 8'); + } + else + { + setorigin(self,trace_endpos+'0 0 38'); + setsize (self, '-8 -8 -38', '8 8 24'); + } + self.nextthink=-1; + return; + } + else + thinktime self : 0.05; +} + +float getBackpackSize(entity item) +{ + float val; + + val = 0; + + val += (item.cnt_torch) + + (item.cnt_h_boost) + + (item.cnt_sh_boost)*3 + + (item.cnt_mana_boost)*2 + + (item.cnt_teleport) + + (item.cnt_tome)*4 + + (item.cnt_summon) + + (item.cnt_invisibility)*3 + + (item.cnt_glyph) + + (item.cnt_haste) + + (item.cnt_blast) + + (item.cnt_polymorph)*2 + + (item.cnt_flight)*2 + + (item.cnt_cubeofforce)*2 + + (item.cnt_invincibility)*10 + + (item.bluemana)/15 + + (item.greenmana)/12 + + (item.spawn_health) + + (item.armor_amulet)/4 + + (item.armor_bracer)/4 + + (item.armor_breastplate)/4 + + (item.armor_helmet)/4; + + return val; +} + + +/* +============ +PlaceItem + +plants the object on the floor +============ +*/ +void() PlaceItem = +{ + float oldz; + float oldHull; + + self.mdl = self.model; // so it can be restored on respawn + self.flags(+)FL_ITEM; // make extra wide + self.solid = SOLID_TRIGGER; + self.movetype = MOVETYPE_TOSS; + setsize (self, self.mins,self.maxs); + self.velocity = '0 0 0'; + self.origin_z = self.origin_z + 6; + oldz = self.origin_z; + if(!self.spawnflags&FLOATING) + { + oldHull=self.hull; + self.hull = HULL_POINT; + if(!droptofloor()) + { + if(self.touch==puzzle_touch) + { + dprintv("Puzzle piece tried to fall out of level at %s\n",self.origin); + setorigin(self,self.wallspot); + } + else + { + dprint ("Item :"); + dprint (self.classname); + dprint (" fell out of level at "); + dprint (vtos(self.origin)); + dprint ("\n"); + remove(self); + } + return; + } + self.hull=oldHull; + if(self.touch==puzzle_touch) + { + setorigin(self,self.origin+'0 0 16'); + setsize (self, '-4 -4 -16', '4 4 0'); + } + else if(self.netname=="Crown") + setsize (self, '-4 -4 0', '4 4 8'); + else + { + setorigin(self,self.origin+'0 0 38'); + setsize (self, '-8 -8 -38', '8 8 24'); + } + } + else + self.movetype = MOVETYPE_NONE; +}; + +/* +============ +StartItem + +Sets the clipping size and plants the object on the floor +============ +*/ +void() StartItem = +{ + if (self.owner) // Spawned by the backpack function + { + self.movetype = MOVETYPE_PUSHPULL; + if(self.touch==puzzle_touch) + setsize (self, '-4 -4 -16', '4 4 0'); + else if(self.netname=="Crown") + setsize (self, '-4 -4 0', '4 4 8'); + else + setsize (self, '-16 -16 -38', '16 16 24'); + if(self.think!=SUB_Remove&&self.owner.classname=="player"&&self.model!="models/bag.mdl") + { + self.think=SUB_Remove; + thinktime self : 30;//Go away after 30 sec if thrown by player & not a backpack + } + } + else + {//key would go here + self.nextthink = time + 0.2; // items start after other solids + self.think = PlaceItem; + } +}; + +/* +//========================================================================= + +//HEALTH BOX + +//========================================================================= +// +// T_Heal: add health to an entity, limiting health to max_health +// "ignore" will ignore max_health limit +// +float (entity e, float healamount, float ignore) T_Heal = +{ + if (e.health <= 0) + return 0; + if ((!ignore) && (e.health >= other.max_health)) + return 0; + healamount = ceil(healamount); + + e.health = e.health + healamount; + if ((!ignore) && (e.health >= other.max_health)) + e.health = other.max_health; + + if (e.health > 250) + e.health = 250; + return 1; +}; + + +//QUAK-ED item_health (.3 .3 1) (0 0 0) (32 32 32) rotten megahealth +//Health box. Normally gives 25 points. Rotten box heals 5-10 points, +//megahealth will add 100 health, then rot you down to your maximum health limit, one point per second. +//-------------------------FIELDS------------------------- + +//-------------------------------------------------------- + + +float H_ROTTEN = 1; +float H_MEGA = 2; +void() health_touch; +void() item_megahealth_rot; + + +//item_megahealth - Added by aleggett for use by the item spawner. +void item_megahealth() +{ + self.touch = health_touch; +//rj setmodel(self, "maps/b_bh100.bsp"); + self.noise = "items/r_item2.wav"; + self.healamount = 100; + self.healtype = 2; + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + StartItem (); +} + +void() health_touch = +{ + local float amount; + local string s; + + if (other.classname != "player"||other.model=="models/sheep.mdl") + return; + + if (self.healtype == 2) // Megahealth? Ignore max_health... + { + if (other.health >= 250) + return; + if (!T_Heal(other, self.healamount, 1)) + return; + } + else + { + if (!T_Heal(other, self.healamount, 0)) + return; + } + + sprint(other, "You receive "); + s = ftos(self.healamount); + sprint(other, s); + sprint(other, " health\n"); + +// health touch sound + sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + self.model = string_null; + self.solid = SOLID_NOT; + + // Megahealth = rot down the player's super health + if (self.healtype == 2) + { + other.items = other.items | IT_SUPERHEALTH; + self.nextthink = time + 5; + self.think = item_megahealth_rot; + self.owner = other; + } + else + { + if (deathmatch != 2) // deathmatch 2 is the silly old rules + { + if (deathmatch) + self.nextthink = time + 20; + self.think = SUB_regen; + } + } + + activator = other; + SUB_UseTargets(); // fire all targets / killtargets +}; + +void() item_megahealth_rot = +{ + other = self.owner; + + if (other.health > other.max_health) + { + other.health = other.health - 1; + self.nextthink = time + 1; + return; + } + +// it is possible for a player to die and respawn between rots, so don't +// just blindly subtract the flag off + other.items = other.items - (other.items & IT_SUPERHEALTH); + + if (deathmatch == 1) // deathmatch 2 is silly old rules + { + self.nextthink = time + 20; + self.think = SUB_regen; + } +}; +*/ + +/* +=============================================================================== + +WEAPONS + +=============================================================================== +*/ + +float MAX_INV = 25; + + +void max_playermana (void) +{ + if (other.bluemana > other.max_mana) + other.bluemana = other.max_mana; + + if (other.greenmana > other.max_mana) + other.greenmana = other.max_mana; +} + + +float(float w) RankForWeapon = +{ + if (w&IT_WEAPON4) + return 1; + if (w == IT_WEAPON3) + return 2; + if (w == IT_WEAPON2) + return 3; + if (w == IT_WEAPON1) + return 4; + return 4; +}; + +/* +============= +Deathmatch_Weapon + +Deathmatch weapon change rules for picking up a weapon + +============= +*/ +void(float old, float new) NewBestWeapon = +{ +float or, nr; + +// change self.weapon if desired + or = RankForWeapon (self.weapon); + nr = RankForWeapon (new); + if ( nr < or ) + { + self.oldweapon = self.weapon;//for deselection animation + if(new&IT_WEAPON4) + self.weapon=IT_WEAPON4; + else + self.weapon = new; + } +}; + +void() W_BestWeapon; + +/* +============= +weapon_touch +============= +*/ +void weapon_touch (void) +{ + float new, old; + entity stemp; + float leave,hadweap; + float scaleVal, numPlayers; + + if (!other.flags & FL_CLIENT)//||other.model=="models/sheep.mdl") + return; + + if ((dmMode == DM_CAPTURE_THE_TOKEN) && (other.gameFlags & GF_HAS_TOKEN)) + { + return; + } + + + if (deathmatch == 2 || coop) + { + if(other.items&self.items) + return; + else + leave = 1; + } + else + leave = 0; + + + new = self.items; + // Give player weapon and mana + if (self.classname=="wp_weapon2") + { + if (other.playerclass == CLASS_PALADIN) + { + self.artifact_name = STR_VORPAL; + self.netname = "wp2"; + } + else if (other.playerclass == CLASS_CRUSADER) + { + self.artifact_name = STR_ICESTAFF; + self.netname = "wp2"; + } + else if (other.playerclass == CLASS_NECROMANCER) + { + self.artifact_name = STR_MAGICMISSILE; + self.netname = "wp2"; + } + else if (other.playerclass == CLASS_ASSASSIN) + { + self.artifact_name = STR_CROSSBOW; + self.netname = "wp2"; + } + else if (other.playerclass == CLASS_SUCCUBUS) + { + self.artifact_name = STR_ACIDORB; + self.netname = "wp2"; + } + + other.bluemana += 25; + } + else if (self.classname=="wp_weapon3") + { + if (other.playerclass == CLASS_PALADIN) + { + self.artifact_name = STR_AXE; + self.netname = "wp3"; + } + else if (other.playerclass == CLASS_CRUSADER) + { + self.artifact_name = STR_METEORSTAFF; + self.netname = "wp3"; + } + else if (other.playerclass == CLASS_NECROMANCER) + { + self.artifact_name = STR_BONESHARD; + self.netname = "wp3"; + } + else if (other.playerclass == CLASS_ASSASSIN) + { + self.artifact_name = STR_GRENADES; + self.netname = "wp3"; + } + else if (other.playerclass == CLASS_SUCCUBUS) + { + self.artifact_name = STR_FLAMEORB; + self.netname = "wp3"; + } + + other.greenmana += 25; + + } + else if (self.classname=="wp_weapon4_head") + { + if (other.playerclass == CLASS_PALADIN) + { + self.artifact_name = STR_PURIFIER1; + self.netname = "wp4a"; + } + else if (other.playerclass == CLASS_CRUSADER) + { + self.artifact_name = STR_SUN1; + self.netname = "wp4a"; + } + else if (other.playerclass == CLASS_NECROMANCER) + { + self.artifact_name = STR_RAVENSTAFF1; + self.netname = "wp4a"; + } + else if (other.playerclass == CLASS_ASSASSIN) + { + self.artifact_name = STR_SET1; + self.netname = "wp4a"; + } + else if (other.playerclass == CLASS_SUCCUBUS) + { + self.artifact_name = STR_LIGHTNING1; + self.netname = "wp4a"; + } + + other.bluemana += 25; + other.greenmana += 25; + + if(easyFourth != 0) + { + other.items (+) IT_WEAPON4_2; + } + if (other.items & IT_WEAPON4_2) + new (+) IT_WEAPON4; + + } + else if (self.classname=="wp_weapon4_staff") + { + if (other.playerclass == CLASS_PALADIN) + { + self.artifact_name = STR_PURIFIER2; + self.netname = "wp4b"; + } + else if (other.playerclass == CLASS_CRUSADER) + { + self.artifact_name = STR_SUN2; + self.netname = "wp4b"; + } + else if (other.playerclass == CLASS_NECROMANCER) + { + self.artifact_name = STR_RAVENSTAFF2; + self.netname = "wp4b"; + } + else if (other.playerclass == CLASS_ASSASSIN) + { + self.artifact_name = STR_SET2; + self.netname = "wp4b"; + } + else if (other.playerclass == CLASS_SUCCUBUS) + { + self.artifact_name = STR_LIGHTNING2; + self.netname = "wp4b"; + } + + other.bluemana += 25; + other.greenmana += 25; + + if(easyFourth != 0) + { + other.items (+) IT_WEAPON4_1; + } + if (other.items & IT_WEAPON4_1) + new (+) IT_WEAPON4; + + } + else + objerror ("weapon_touch: unknown classname"); + + sprinti (other, PRINT_MEDIUM, STR_YOUGOTTHE); + sprinti (other, PRINT_MEDIUM, self.artifact_name); + sprint (other, PRINT_MEDIUM, "\n"); + + sound (other, CHAN_ITEM, "weapons/weappkup.wav", 1, ATTN_NORM); // touch sound + stuffcmd (other, "bf\n"); + + max_playermana (); // Check mana limits + +// change to the weapon + if(other.items&new) + hadweap=TRUE; + + old = other.items; + other.items = other.items | new; + + stemp = self; + self = other; + + max_playermana(); + + if(self.attack_finished other.max_health) + other.health = other.max_health; + + self.model = string_null; + self.solid = SOLID_NOT; + if (deathmatch == 1||dmMode==DM_SIEGE) + { + if(patternRunner) + { + scaleVal = 1.0; + } + else + { + numPlayers = countPlayers(); + + scaleVal = 2.0 - (numPlayers * .125); + if(scaleVal < .2) + { + scaleVal = .2; + } + } + self.nextthink = time + RESPAWN_TIME*scaleVal; + } + self.think = SUB_regen; + + sprinti(other, PRINT_MEDIUM, STR_YOUHAVETHE); + sprinti(other,PRINT_MEDIUM, self.artifact_name); + sprint(other,PRINT_MEDIUM, "\n"); + + activator = other; + SUB_UseTargets(); // fire all targets / killtargets + } + if(other.flags2&FL2_POISONED) + { + other.flags2(-)FL2_POISONED; + centerprint(other,"The poison has been cleansed from your blood...\n"); + } +} + + +void spawn_instant_health(void) +{ + self.touch = ihealth_touch; + setmodel (self, "models/i_hboost.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.classname = "item_health"; + self.artifact_name = STR_INSTANTHEALTH; + self.netname = "blue health"; + StartItem (); +} + +/*QUAKED item_health (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING +Player is given 10 health instantly +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_health (void) +{ + spawn_instant_health(); +} + +void mana_touch(void) +{ + float scaleVal, numPlayers; + + if ((other.classname!="player") || (other.health < 1))//||other.model=="models/sheep.mdl") + return; + + if ((dmMode == DM_CAPTURE_THE_TOKEN) && (other.gameFlags & GF_HAS_TOKEN)) + { + return; + } + + if (self.owner == other && self.artifact_ignore_owner_time > time) + return; + if (self.artifact_ignore_time > time) + return; + + if ((self.classname == "item_mana_green") && (other.greenmana >= other.max_mana)) + return; + + if ((self.classname == "item_mana_blue") && (other.bluemana >= other.max_mana)) + return; + + if ((self.classname == "item_mana_both") && (other.bluemana >= other.max_mana) && (other.greenmana >= other.max_mana)) + return; + + sprinti(other, PRINT_MEDIUM, STR_YOUHAVETHE); + sprinti(other,PRINT_MEDIUM, self.artifact_name); + sprint(other,PRINT_MEDIUM, "\n"); + + sound (other, CHAN_VOICE, "items/itempkup.wav", 1, ATTN_NORM); + stuffcmd (other, "bf\n"); + + if (self.classname == "item_mana_green") + other.greenmana += self.count; + else if (self.classname == "item_mana_blue") + other.bluemana += self.count; + else + { + other.greenmana += self.count; + other.bluemana += self.count; + } + + max_playermana(); + + self.model = string_null; + self.solid = SOLID_NOT; + self.think = SUB_regen; + + activator = other; + SUB_UseTargets(); // fire all targets / killtargets + if (!self.owner && (deathmatch == 1||dmMode==DM_SIEGE)) //if it has an owner, it was dropped when he was killed so don't respawn + { + if(patternRunner) + { + scaleVal = 1.0; + } + else + { + numPlayers = countPlayers(); + + scaleVal = 2.0 - (numPlayers * .125); + if(scaleVal < .2) + { + scaleVal = .2; + } + } + self.nextthink = time + RESPAWN_TIME*scaleVal; + } + else + remove(self); +} + +void spawn_item_mana_green(float amount) +{ + setmodel (self, "models/i_gmana.mdl"); + self.touch = mana_touch; + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.classname = "item_mana_green"; + self.artifact_name = STR_GREENMANA; + self.netname = "gmana"; + self.count=amount; + StartItem (); +} + +/*QUAKED item_mana_green (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING BIG +Player is given 15 green mana instantly +BIG = 30 mana. +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void item_mana_green (void) +{ + if(self.spawnflags&2) + { + self.drawflags(+)SCALE_ORIGIN_CENTER|MLS_POWERMODE; + self.scale=2; + spawn_item_mana_green(30); + } + else + spawn_item_mana_green(15); +} + + +void spawn_item_mana_blue(float amount) +{ + self.touch = mana_touch; + setmodel (self, "models/i_bmana.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.classname = "item_mana_blue"; + self.count=amount; + self.artifact_name = STR_BLUEMANA; + self.netname = "bmana"; + StartItem (); +} + +/*QUAKED item_mana_blue (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING BIG +Player is given 15 blue mana instantly +BIG = 30 +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_mana_blue (void) +{ + if(self.spawnflags&2) + { + self.drawflags(+)SCALE_ORIGIN_CENTER|MLS_POWERMODE; + self.scale=2; + spawn_item_mana_blue(30); + } + else + spawn_item_mana_blue(15); +} + +void spawn_item_mana_both(float amount) +{ + self.touch = mana_touch; + setmodel (self, "models/i_btmana.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.classname = "item_mana_both"; + self.count=amount; + self.artifact_name = STR_COMBINEDMANA; + self.netname = "cmana"; + StartItem (); +} + +/*QUAKED item_mana_both (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING BIG +Player is given 15 green and 10 blue mana instantly +BIG = 30 each +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_mana_both (void) +{ + if(self.spawnflags&2) + { + self.drawflags(+)SCALE_ORIGIN_CENTER|MLS_POWERMODE; + self.scale=2; + spawn_item_mana_both(30); + } + else + spawn_item_mana_both(15); +} + + + +/* +=============================================================================== + +ARMOR + +=============================================================================== +*/ + +void armor_touch(void) +{ + float scaleVal, numPlayers; + + if((other.classname != "player") || (other.health <= 0))//||other.model=="models/sheep.mdl") + { + return; + } + + if ((dmMode == DM_CAPTURE_THE_TOKEN) && (other.gameFlags & GF_HAS_TOKEN)) + { + return; + } + + if(self.classname == "item_armor_amulet") + { + other.armor_amulet = 20; + } + else if(self.classname == "item_armor_bracer") + { + other.armor_bracer = 20; + } + else if(self.classname == "item_armor_breastplate") + { + other.armor_breastplate = 20; + } + else if(self.classname == "item_armor_helmet") + { + other.armor_helmet = 20; + } + + self.solid = SOLID_NOT; + self.model = string_null; + if(deathmatch == 1||dmMode==DM_SIEGE) + { + if(patternRunner) + { + scaleVal = 1.0; + } + else + { + numPlayers = countPlayers(); + + scaleVal = 2.0 - (numPlayers * .125); + if(scaleVal < .2) + { + scaleVal = .2; + } + } + self.nextthink = time + RESPAWN_TIME*scaleVal; + } + self.think = SUB_regen; + + sprinti(other, PRINT_MEDIUM, STR_YOUHAVETHE); + sprinti(other, PRINT_MEDIUM, self.artifact_name); + sprint(other, PRINT_MEDIUM, "\n"); + + sound(other, CHAN_ITEM, "items/armrpkup.wav", 1, ATTN_NORM); + stuffcmd(other, "bf\n"); + + activator = other; + SUB_UseTargets(); +} + + +void spawn_item_armor_helmet(void) +{ + setmodel (self, "models/i_helmet.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.touch = armor_touch; + self.artifact_name = STR_ARMORHELMET; + self.netname = "helm"; + + StartItem (); +} + +/*QUAKED item_armor_helmet (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_armor_helmet (void) +{ + spawn_item_armor_helmet(); +} + +void spawn_item_armor_breastplate (void) +{ + setmodel (self, "models/i_bplate.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.touch = armor_touch; + self.artifact_name = STR_ARMORBREASTPLATE; + self.netname = "brplate"; + + StartItem (); +} + +/*QUAKED item_armor_breastplate (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_armor_breastplate (void) +{ + spawn_item_armor_breastplate(); +} + +void spawn_item_armor_bracer(void) +{ + setmodel (self, "models/i_bracer.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.touch = armor_touch; + self.artifact_name = STR_ARMORBRACER; + self.netname = "armlet"; + + StartItem (); +} + +/*QUAKED item_armor_bracer (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_armor_bracer (void) +{ + spawn_item_armor_bracer(); +} + +void spawn_item_armor_amulet(void) +{ + setmodel (self, "models/i_amulet.mdl"); + setsize (self, '0 0 0', '0 0 0'); + self.hull=HULL_POINT; + self.touch = armor_touch; + self.netname = "amulet"; + self.artifact_name = STR_ARMORAMULET; + + StartItem (); +} + +/*QUAKED item_armor_amulet (0 .5 .8) (-8 -8 -45) (8 8 20) FLOATING +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void item_armor_amulet (void) +{ + spawn_item_armor_amulet(); +} + + +/* +=============================================================================== + +PLAYER BACKPACKS + +=============================================================================== +*/ + +void GetPuzzle2(entity item, entity person, string which); + +void BackpackTouch(void) +{ + string s; + float old, new; + float ItemCount; + float itemRoom; + float removeMe,old_cnt; + + if (other.classname != "player")//||other.model=="models/sheep.mdl") + return; + + if ((dmMode == DM_CAPTURE_THE_TOKEN) && (other.gameFlags & GF_HAS_TOKEN)) + { + return; + } + + if (other.health <= 0) + return; + if (self.owner == other && self.artifact_ignore_owner_time > time) + return; + if (self.artifact_ignore_time > time) + return; + + removeMe = TRUE; + ItemCount = 0; + + if (self.cnt_torch > 0) + { + itemRoom = roomForItem(other,STR_TORCH); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_torch) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_torch; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_TORCH, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_TORCH); + if (itemRoom > 1) // Plural + sprint(other,PRINT_MEDIUM, "es"); + self.cnt_torch = self.cnt_torch - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_h_boost > 0) + { + itemRoom = roomForItem(other,STR_HEALTHBOOST); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_h_boost) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_h_boost; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_HEALTHBOOST, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_HEALTHBOOST); + if (itemRoom > 1) // Plural + sprint(other,PRINT_MEDIUM, "s"); + self.cnt_h_boost = self.cnt_h_boost - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_sh_boost > 0) + { + itemRoom = roomForItem(other,STR_SUPERHEALTHBOOST); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_sh_boost) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_sh_boost; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_SUPERHEALTHBOOST, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_SUPERHEALTHBOOST); + if (itemRoom > 1) // Plural + sprint(other,PRINT_MEDIUM, "s"); + self.cnt_sh_boost = self.cnt_sh_boost - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_mana_boost > 0) + { + itemRoom = roomForItem(other,STR_MANABOOST); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_mana_boost) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_mana_boost; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_MANABOOST, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_MANABOOST); + else + sprint(other,PRINT_MEDIUM, "Kraters of Might"); + self.cnt_mana_boost = self.cnt_mana_boost - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_teleport > 0) + { + itemRoom = roomForItem(other,STR_TELEPORT); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_teleport) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_teleport; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_TELEPORT, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_TELEPORT); + if (itemRoom > 1) // Plural + sprint(other,PRINT_MEDIUM, "s"); + self.cnt_teleport = self.cnt_teleport - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_tome > 0) + { + itemRoom = roomForItem(other,STR_TOME); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_tome) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_tome; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_TOME, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_TOME); + else + sprint(other,PRINT_MEDIUM, "Tomes of Power"); + self.cnt_tome = self.cnt_tome - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_summon > 0) + { + itemRoom = roomForItem(other,STR_SUMMON); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_summon) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_summon; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_SUMMON, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_SUMMON); + else + sprint(other,PRINT_MEDIUM, "Stones of Summoning"); + self.cnt_summon = self.cnt_summon - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_flight > 0) + { + itemRoom = roomForItem(other,STR_RINGFLIGHT); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_flight) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_flight; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_RINGFLIGHT, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_RINGFLIGHT); + else + sprint(other,PRINT_MEDIUM, "Rings of Flight"); + self.cnt_flight = self.cnt_flight - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_glyph > 0) + { + itemRoom = roomForItem(other,STR_GLYPH); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_glyph) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_glyph; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_GLYPH, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_GLYPH); + else + sprint(other,PRINT_MEDIUM, "Glyphs Of The Ancients"); + self.cnt_glyph = self.cnt_glyph - itemRoom; + } + else + { + removeMe = FALSE; + } + } + + if (self.cnt_haste > 0) + { + itemRoom = roomForItem(other,STR_HASTE); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_haste) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_haste; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_HASTE, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_HASTE); + self.cnt_haste = self.cnt_haste - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_blast > 0) + { + itemRoom = roomForItem(other,STR_BLAST); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_blast) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_blast; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_BLAST, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_BLAST); + else + sprint(other,PRINT_MEDIUM, "Discs of Repulsion"); + self.cnt_blast = self.cnt_blast - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_polymorph > 0) + { + itemRoom = roomForItem(other,STR_POLYMORPH); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_polymorph) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_polymorph; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_POLYMORPH, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_POLYMORPH); + else + sprint(other,PRINT_MEDIUM, "Seals of the Ovinomancer"); + self.cnt_polymorph = self.cnt_polymorph - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_invisibility > 0) + { + itemRoom = roomForItem(other,STR_INVISIBILITY); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_invisibility) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_invisibility; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_INVISIBILITY, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_INVISIBILITY); + if (itemRoom > 1) + sprint(other,PRINT_MEDIUM, "s"); + self.cnt_invisibility = self.cnt_invisibility - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_cubeofforce > 0) + { + itemRoom = roomForItem(other,STR_CUBEOFFORCE); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_cubeofforce) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_cubeofforce; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_CUBEOFFORCE, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_CUBEOFFORCE); + if (itemRoom > 1) + sprint(other,PRINT_MEDIUM, "s"); + self.cnt_cubeofforce = self.cnt_cubeofforce - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.cnt_invincibility > 0) + { + itemRoom = roomForItem(other,STR_INVINCIBILITY); + + if (itemRoom > 0) + { + if (itemRoom < self.cnt_invincibility) + { + removeMe = FALSE; + } + else + { + itemRoom = self.cnt_invincibility; + } + + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + adjustInventoryCount(other, STR_INVINCIBILITY, itemRoom); + s = ftos(itemRoom); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + if (itemRoom == 1) + sprinti(other,PRINT_MEDIUM, STR_INVINCIBILITY); + else + sprint(other,PRINT_MEDIUM, "Icons of the Defender"); + self.cnt_invincibility = self.cnt_invincibility - itemRoom; + } + else + { + removeMe = FALSE; + } + } + if (self.bluemana > 0) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + other.bluemana += self.bluemana; + + s = ftos(self.bluemana); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_BLUEMANA); + + self.bluemana = 0; + } + if (self.greenmana > 0) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + other.greenmana += self.greenmana; + + s = ftos(self.greenmana); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_GREENMANA); + + self.greenmana = 0; + } + if (self.cnt_arrows > 0&&other.cnt_arrows<100) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + old_cnt = other.cnt_arrows; + other.cnt_arrows+= self.cnt_arrows; + if(other.cnt_arrows>100) + { + self.cnt_arrows=other.cnt_arrows - 100; + other.cnt_arrows = 100; + } + else + self.cnt_arrows = 0; + + s = ftos(other.cnt_arrows-old_cnt); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_ARROWS); + } + if (self.cnt_grenades > 0&&other.cnt_grenades<45) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + old_cnt = other.cnt_grenades; + other.cnt_grenades+= self.cnt_grenades; + if(other.cnt_grenades>100) + { + self.cnt_grenades=other.cnt_grenades - 100; + other.cnt_grenades = 100; + } + else + self.cnt_grenades = 0; + + s = ftos(other.cnt_grenades-old_cnt); + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_GRENADES); + } + + if (self.armor_amulet) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + other.armor_amulet = self.armor_amulet; + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_ARMORAMULET); + + self.armor_amulet = 0; + } + + if (self.armor_bracer) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + other.armor_bracer = self.armor_bracer; + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_ARMORBRACER); + + self.armor_bracer = 0; + } + + if (self.armor_breastplate) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + other.armor_breastplate = self.armor_breastplate; + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_ARMORBREASTPLATE); + + self.armor_breastplate = 0; + } + + if (self.armor_helmet) + { + if (ItemCount) sprint(other,PRINT_MEDIUM, ", "); + else sprint (other, PRINT_MEDIUM, "You get "); + ItemCount += 1; + + other.armor_helmet = self.armor_helmet; + sprint(other,PRINT_MEDIUM, s); + sprint(other,PRINT_MEDIUM, " "); + sprinti(other,PRINT_MEDIUM, STR_ARMORHELMET); + + self.armor_helmet = 0; + } + + if (!ItemCount) + { + if (removeMe) + { + sprint(other,PRINT_MEDIUM, "You get...Nothing!"); + } + else + { + 8; +// sprint(other,PRINT_MEDIUM, "...Nothing you have room to carry!"); + } + } +/* else + { + self.scale = getBackpackSize(self) * 4.0 * 0.01; + if(self.scale > 2.4)self.scale = 2.4; + if(self.scale < .3)self.scale = .3; + }*/ + +// if the player was using his best weapon, change up to the new one if better + + new = self.items; + if (!new) + new = other.weapon; + old = other.items; + other.items (+) new; + +// change weapons + + if (ItemCount || removeMe) + { + sprint (other, PRINT_MEDIUM, "\n"); + + // backpack touch sound + sound (other, CHAN_ITEM, "weapons/ammopkup.wav", 1, ATTN_NORM); + stuffcmd (other, "bf\n"); + } + +// remove the backpack, change self to the player + if (removeMe) + { + remove(self); + } + + self = other; + +// change to the weapon + if (!deathmatch) + self.weapon = new; + else + NewBestWeapon (old, new); + + W_SetCurrentWeapon (); +} + +void MonsterDropStuff(void) +{ + float chance; + + if(!self.flags&FL_MONSTER) + return; + + if (self.monsterclass < CLASS_GRUNT) + return; + + // Grunts drop only instant items + if (self.monsterclass == CLASS_GRUNT) + { + if (random() < .15) // %15 chance he'll drop something + { + chance = random(); + if (chance < .25) + self.greenmana = 10; + else if (chance < .50) + self.bluemana = 10; + else if (chance < .75) + { + self.greenmana = 10; + self.bluemana = 10; + } + else + { + self.spawn_health = 1; + } + } + } + + // Henchmen drop instant items or lesser artifacts + else if (self.monsterclass == CLASS_HENCHMAN) + { + if (random() < .15) // %15 chance he'll drop something + { + chance = random(); + + if (chance < .08) + self.greenmana = 10; + else if (chance < .16) + self.bluemana = 10; + else if (chance < .24) + { + self.greenmana = 10; + self.bluemana = 10; + } + else if (chance < .32) + { + self.spawn_health = 1; + } + else if (chance < .40) + self.cnt_torch = 1; + else if (chance < .48) + self.cnt_h_boost = 1; + else if (chance < .56) + self.cnt_mana_boost = 1; + else if (chance < .64) + self.cnt_teleport = 1; + else if (chance < .72) + self.cnt_tome = 1; + else if (chance < .80) + self.cnt_haste = 1; + else if (chance < .90) + self.cnt_blast = 1; + } + } + // Leaders drop armor or artifacts + else if (self.monsterclass == CLASS_LEADER) + { + if (random() < .15) // %15 chance he'll drop something + { + chance = random(); + + if (chance < .05) + self.cnt_torch = 1; + else if (chance < .10) + self.cnt_h_boost = 1; + else if (chance < .15) + self.cnt_sh_boost = 1; + else if (chance < .20) + self.cnt_mana_boost = 1; + else if (chance < .25) + self.cnt_teleport = 1; + else if (chance < .30) + self.cnt_tome = 1; + else if (chance < .35) + self.cnt_summon = 1; + else if (chance < .40) + self.cnt_invisibility = 1; + else if (chance < .45) + self.cnt_glyph = 1; + else if (chance < .50) + self.cnt_haste = 1; + else if (chance < .55) + self.cnt_blast = 1; + else if (chance < .60) + self.cnt_polymorph = 1; + else if (chance < .65) + self.cnt_cubeofforce = 1; + else if (chance < .70) + self.cnt_invincibility = 1; + else if (chance < .75) + self.armor_amulet = 20; + else if (chance < .80) + self.armor_bracer = 20; + else if (chance < .85) + self.armor_breastplate = 20; + else + self.armor_helmet = 20; + } + } + + DropBackpack(); +} + + + +void spawn_weapon2 (void) +{ + entity newEnt; + + newEnt = spawn(); + + CreateEntityNew(newEnt,ENT_WEAPON2_ART,"models/w_l2_c1.mdl",SUB_Null); + newEnt.hull=HULL_POINT; + newEnt.classname="wp_weapon2"; + + newEnt.flags(+)FL_CLASS_DEPENDENT; + newEnt.touch = weapon_touch; + newEnt.items=IT_WEAPON2; + + newEnt.movetype = MOVETYPE_PUSHPULL; + setsize (newEnt, '-16 -16 -38', '16 16 24'); + + newEnt.think=SUB_Remove; + thinktime newEnt : 30; + + newEnt.origin = self.origin; + newEnt.origin_z += 32; + newEnt.velocity_x = random(-50, 50); + newEnt.velocity_y = random(-50, 50); + newEnt.velocity_z = 300; + newEnt.flags(-)FL_ONGROUND; +} + +void spawn_weapon3 (void) +{ + entity newEnt; + + newEnt = spawn(); + + CreateEntityNew(newEnt,ENT_WEAPON3_ART,"models/w_l3_c1.mdl",SUB_Null); + newEnt.hull=HULL_POINT; + newEnt.classname="wp_weapon3"; + + newEnt.flags(+)FL_CLASS_DEPENDENT; + newEnt.touch = weapon_touch; + newEnt.items=IT_WEAPON3; + + newEnt.movetype = MOVETYPE_PUSHPULL; + //setsize (newEnt, '-16 -16 -38', '16 16 24'); + setsize (newEnt, '-16 -16 -38', '16 16 24'); + + newEnt.think=SUB_Remove; + thinktime newEnt : 30; + + newEnt.origin = self.origin; + newEnt.origin_z += 32; + newEnt.velocity_x = random(-50, 50); + newEnt.velocity_y = random(-50, 50); + newEnt.velocity_z = 300; + newEnt.flags(-)FL_ONGROUND; + +} + +void spawn_weapon4_head (void) +{ + entity newEnt; + + newEnt = spawn(); + + CreateEntityNew(newEnt,ENT_WEAPON41_ART,"models/w_l41_c1.mdl",SUB_Null); + newEnt.hull=HULL_POINT; + newEnt.classname="wp_weapon4_head"; + + newEnt.flags(+)FL_CLASS_DEPENDENT; + newEnt.touch = weapon_touch; + newEnt.items=IT_WEAPON4_1; + + newEnt.movetype = MOVETYPE_PUSHPULL; + setsize (newEnt, '-16 -16 -38', '16 16 24'); + + newEnt.think=SUB_Remove; + thinktime newEnt : 30; + + newEnt.origin = self.origin; + newEnt.origin_z += 32; + newEnt.velocity_x = random(-50, 50); + newEnt.velocity_y = random(-50, 50); + newEnt.velocity_z = 300; + newEnt.flags(-)FL_ONGROUND; +} + +void spawn_weapon4_staff (void) +{ + entity newEnt; + + newEnt = spawn(); + + CreateEntityNew(newEnt,ENT_WEAPON42_ART,"models/w_l42_c1.mdl",SUB_Null); + newEnt.hull=HULL_POINT; + newEnt.classname="wp_weapon4_staff"; + + newEnt.flags(+)FL_CLASS_DEPENDENT; + newEnt.touch = weapon_touch; + newEnt.items=IT_WEAPON4_2; + + newEnt.movetype = MOVETYPE_PUSHPULL; + setsize (newEnt, '-16 -16 -38', '16 16 24'); + + newEnt.think=SUB_Remove; + thinktime newEnt : 30; + + newEnt.origin = self.origin; + newEnt.origin_z += 32; + newEnt.velocity_x = random(-50, 50); + newEnt.velocity_y = random(-50, 50); + newEnt.velocity_z = 300; + newEnt.flags(-)FL_ONGROUND; +} + +/* +=============== +DropBackpack +=============== +*/ +void DropBackpack(void) +{ + entity item;//,old_self; + float total; + float dropThreshhold; + +/* if(altRespawn) + { + dropThreshhold = .5; + } + else + { + dropThreshhold = -1; + }*/ + +/* if((dmMode == DM_CAPTURE_THE_TOKEN)&&(self.gameFlags & GF_HAS_TOKEN)) + { + self.gameFlags (-) GF_HAS_TOKEN; + //bprint(PRINT_MEDIUM, self.netname); + //bprint(PRINT_MEDIUM, " dropped the Icon...\n"); + //bcenterprint(self.netname); + //bcenterprint(" dropped the Icon...\n"); + bcenterprint2(self.netname, " dropped the Icon...\n"); + spawnNewDmToken(self, 0); + }*/ + + item = spawn(); + + total = 0; + + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_torch > 3) + total += item.cnt_torch = 3; + else + total += item.cnt_torch = self.cnt_torch; + + self.cnt_torch=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_h_boost > 3) + total += item.cnt_h_boost = 3; + else + total += item.cnt_h_boost = self.cnt_h_boost; + + self.cnt_h_boost=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_sh_boost > 3) + total += item.cnt_sh_boost = 3; + else + total += item.cnt_sh_boost = self.cnt_sh_boost; + + self.cnt_sh_boost=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_mana_boost > 3) + total += item.cnt_mana_boost = 3; + else + total += item.cnt_mana_boost = self.cnt_mana_boost; + + self.cnt_mana_boost=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_teleport > 3) + total += item.cnt_teleport = 3; + else + total += item.cnt_teleport = self.cnt_teleport; + + self.cnt_teleport=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_tome=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_summon=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_invisibility=0; + } + + + if(random(0,1) > dropThreshhold) + { + if(self.playerclass==CLASS_CRUSADER) + self.cnt_glyph=rint(self.cnt_glyph/5); + if (self.cnt_glyph > 3) + total += item.cnt_glyph = 3; + else + total += item.cnt_glyph = self.cnt_glyph; + + self.cnt_glyph=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_haste=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_blast=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_polymorph=0; + } + + + if(random(0,1) > dropThreshhold) + { + self.cnt_flight=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_cubeofforce > 3) + total += item.cnt_cubeofforce = 3; + else + total += item.cnt_cubeofforce = self.cnt_cubeofforce; + + self.cnt_cubeofforce=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.cnt_invincibility > 3) + total += item.cnt_invincibility = 3; + else + total += item.cnt_invincibility = self.cnt_invincibility; + + self.cnt_invincibility=0; + } + + if(random(0,1) > dropThreshhold) + { + // Full armor on this body? + if (self.armor_amulet==20) + { + total += 1; + item.armor_amulet = self.armor_amulet; + } + self.armor_amulet=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.armor_bracer==20) + { + total += 1; + item.armor_bracer = self.armor_bracer; + } + self.armor_bracer=0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.armor_breastplate==20) + { + total += 1; + item.armor_breastplate = self.armor_breastplate; + } + self.armor_breastplate = 0; + } + + + if(random(0,1) > dropThreshhold) + { + if (self.armor_helmet==20) + { + total += 1; + item.armor_helmet = self.armor_helmet; + } + self.armor_helmet = 0; + } + +/* if (self.puzzle_inv1) + { + item.puzzle_inv1 = self.puzzle_inv1; + total = 999; + } + if (self.puzzle_inv2) + { + item.puzzle_inv2 = self.puzzle_inv2; + total = 999; + } + if (self.puzzle_inv3) + { + item.puzzle_inv3 = self.puzzle_inv3; + total = 999; + } + if (self.puzzle_inv4) + { + item.puzzle_inv4 = self.puzzle_inv4; + total = 999; + } + if (self.puzzle_inv5) + { + item.puzzle_inv5 = self.puzzle_inv5; + total = 999; + } + if (self.puzzle_inv6) + { + item.puzzle_inv6 = self.puzzle_inv6; + total = 999; + } + if (self.puzzle_inv7) + { + item.puzzle_inv7 = self.puzzle_inv7; + total = 999; + } + if (self.puzzle_inv8) + { + item.puzzle_inv8 = self.puzzle_inv8; + total = 999; + } +*/ + + // Any mana or instant health +/* if(altRespawn) + { + self.bluemana *= .5; + self.greenmana *= .5; + self.spawn_health *= .5; + + item.bluemana = self.bluemana; + item.greenmana = self.greenmana; + item.spawn_health = self.spawn_health; + + // These will all currently respawn :[ + + if(self.items & IT_WEAPON4) + { + self.items(-)IT_WEAPON4|IT_WEAPON4_1|IT_WEAPON4_2; + + if(altRespawn) + { + if(random(0,1) < .5) + { + spawn_weapon4_staff(); + } + else + { + spawn_weapon4_head(); + } + } + + } + if(self.items & IT_WEAPON3) + { + if((random(0,1) > .5)||(self.weapon == IT_WEAPON3)) + { + self.items(-)IT_WEAPON3; + + spawn_weapon3(); + } + } + if(self.items & IT_WEAPON2) + { + if((random(0,1) > .5)||(self.weapon == IT_WEAPON2)) + { + self.items(-)IT_WEAPON2; + + spawn_weapon2(); + } + } + } + else + {*/ +// item.bluemana = self.bluemana; +// item.greenmana = self.greenmana; + item.cnt_arrows=self.cnt_arrows; + item.cnt_grenades=self.cnt_grenades; + item.spawn_health = self.spawn_health; + + self.cnt_arrows = 0; + self.cnt_grenades = 0; + self.bluemana=0; + self.greenmana=0; + self.spawn_health=0; +// } + +// total = 1; +// item.cnt_tome = 1; + + if (!total && !item.cnt_grenades&&!item.cnt_arrows&&!item.bluemana && !item.greenmana && !item.spawn_health) + { // Nothing to put in the backpack + remove(item); + return; + } + else + total=TRUE; + + setorigin(item,self.origin); + item.origin = self.origin + '0 0 40'; + item.flags(+)FL_ITEM; + item.solid = SOLID_TRIGGER; + item.movetype = MOVETYPE_TOSS; + item.owner = self; + item.artifact_ignore_owner_time = time + 2; + item.artifact_ignore_time = time + 0.1; + +//Always throw BP in Siege +/* if ((total == 1 && !item.bluemana && !item.greenmana && !item.spawn_health) || + (total == 0 && item.bluemana && !item.greenmana && !item.spawn_health) || + (total == 0 && !item.bluemana && item.greenmana && !item.spawn_health) || + (total == 0 && !item.bluemana && !item.greenmana && item.spawn_health)) + { // throw out the individual item + item.velocity_z = 200; +// item.velocity_x = random(-20,20); +// item.velocity_y = random(-20,20); + + old_self = self; + self = item; + + if (item.cnt_torch) + { + spawn_artifact(ARTIFACT_TORCH,NO_RESPAWN); + } + else if (item.cnt_h_boost) + { + spawn_artifact(ARTIFACT_HP_BOOST,NO_RESPAWN); + } + else if (item.cnt_sh_boost) + { + spawn_artifact(ARTIFACT_SUPER_HP_BOOST,NO_RESPAWN); + } + else if (item.cnt_mana_boost) + { + spawn_artifact(ARTIFACT_MANA_BOOST,NO_RESPAWN); + } + else if (item.cnt_teleport) + { + spawn_artifact(ARTIFACT_TELEPORT,NO_RESPAWN); + } + else if (item.cnt_tome) + { + spawn_artifact(ARTIFACT_TOME,NO_RESPAWN); + } + else if (item.cnt_summon) + { + spawn_artifact (ARTIFACT_SUMMON,NO_RESPAWN); + } + else if (item.cnt_invisibility) + { + spawn_artifact (ARTIFACT_INVISIBILITY,NO_RESPAWN); + } + else if (item.cnt_glyph) + { + spawn_artifact (ARTIFACT_GLYPH,NO_RESPAWN); + } + else if (item.cnt_haste) + { + spawn_artifact (ARTIFACT_HASTE,NO_RESPAWN); + } + else if (item.cnt_blast) + { + spawn_artifact(ARTIFACT_BLAST,NO_RESPAWN); + } + else if (item.cnt_polymorph) + { + spawn_artifact (ARTIFACT_POLYMORPH,NO_RESPAWN); + } + else if (item.cnt_flight) + { + spawn_artifact (ARTIFACT_FLIGHT,NO_RESPAWN); + } + else if (item.cnt_cubeofforce) + { + spawn_artifact (ARTIFACT_CUBEOFFORCE,NO_RESPAWN); + } + else if (item.cnt_invincibility) + { + spawn_artifact (ARTIFACT_INVINCIBILITY,NO_RESPAWN); + } + //can never happen +// else if ((item.bluemana) && (item.greenmana)) +// { +// spawn_item_mana_both(self.bluemana); +// } +// + else if (item.bluemana) + { + spawn_item_mana_blue(self.bluemana); + } + else if (item.greenmana) + { + spawn_item_mana_green(self.greenmana); + } + else if (item.spawn_health) + { + spawn_instant_health(); + } + else if (item.armor_amulet) + { + spawn_item_armor_amulet(); + } + else if (item.armor_bracer) + { + spawn_item_armor_bracer(); + } + else if (item.armor_breastplate) + { + spawn_item_armor_breastplate(); + } + else if (item.armor_helmet) + { + spawn_item_armor_helmet(); + } + else + { + dprint("Bad backpack!"); + remove(item); + self = old_self; + return; + } + + self = old_self; + } + else + {*/ + item.velocity_z = 300; + + setmodel (item, "models/bag.mdl"); + setsize (item, '-16 -16 -45', '16 16 10'); + item.hull=HULL_POINT; + item.touch = BackpackTouch; + + item.nextthink = time + 120; // remove after 2 minutes + item.think = SUB_Remove; + +// item.scale = getBackpackSize(item) * 4.0 * 0.01; +// if(item.scale > 2.4)item.scale = 2.4; +// if(item.scale < .15)item.scale = .15; + + if (!total) + { + remove(item); + return; + } +// } +} + diff --git a/javelin.hc b/javelin.hc new file mode 100644 index 0000000..6dc8717 --- /dev/null +++ b/javelin.hc @@ -0,0 +1,131 @@ +/* + * $Header: /HexenWorld/Siege/javelin.hc 3 5/25/98 1:39p Mgummelt $ + */ +/* +============================================================================== + +GAUNTLET + +============================================================================== +*/ +$cd q:/art/models/weapons/javelin/final +$origin 0 5 10 +//$rotatehtr 90 180 0 +$base base skin +$skin skin + +$frame jav000 jav001 jav002 jav003 jav004 +$frame jav005 jav006 jav007 jav008 jav009 +$frame jav010 jav011 jav012 jav013 jav014 +$frame jav015 jav016 jav017 jav018 +$frame jav019 jav020 + +void() W_FireJavelin; +void() T_MissileTouch; + +//============================================================================ +void() throwjav0 =[ $jav000, throwjav1 ] {self.weaponframe=0;}; +void() throwjav1 =[ $jav001, throwjav2 ] {self.weaponframe=1;}; +void() throwjav2 =[ $jav002, throwjav3 ] {self.weaponframe=2;}; +void() throwjav3 =[ $jav003, throwjav4 ] {self.weaponframe=3;}; +void() throwjav4 =[ $jav004, throwjav5 ] {self.weaponframe=4;}; +void() throwjav5 =[ $jav005, throwjav6 ] {self.weaponframe=5;}; +void() throwjav6 =[ $jav006, throwjav7 ] {self.weaponframe=6;}; +void() throwjav7 =[ $jav007, throwjav8 ] {self.weaponframe=7;}; +void() throwjav8 =[ $jav008, throwjav9 ] {self.weaponframe=8;}; +void() throwjav9 =[ $jav009, throwjav10 ] {self.weaponframe=9;W_FireJavelin();}; +void() throwjav10 =[ $jav010, throwjav11 ] {self.weaponframe=10;}; +void() throwjav11 =[ $jav011, throwjav12 ] {self.weaponframe=11;}; +void() throwjav12 =[ $jav012, throwjav13 ] {self.weaponframe=12;}; +void() throwjav13 =[ $jav013, throwjav14 ] {self.weaponframe=13;}; +void() throwjav14 =[ $jav014, throwjav15 ] {self.weaponframe=14;}; +void() throwjav15 =[ $jav015, throwjav16 ] {self.weaponframe=15;}; +void() throwjav16 =[ $jav016, throwjav17 ] {self.weaponframe=16;}; +void() throwjav17 =[ $jav017, throwjav18 ] {self.weaponframe=17;}; +void() throwjav18 =[ $jav018, throwjav19 ] {self.weaponframe=18;}; +void() throwjav19 =[ $jav019, throwjav20 ] {self.weaponframe=19;}; +void() throwjav20 =[ $jav020, self.th_run ] {self.weaponframe=20;}; + + +//============================================================================ +/* +================================ +launch_javelin + +================================ +*/ +void(vector org, vector dir) launch_javelin = +{ + local entity missile; + + missile = spawn (); + missile.owner = self; + missile.touch = T_MissileTouch; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + + missile.angles = vectoangles(dir); + + missile.touch = T_MissileTouch; + missile.classname = "javelin"; + + org = org + '0 10 10'; + setmodel (missile, "models/javproj.mdl"); + setsize (missile, VEC_ORIGIN, VEC_ORIGIN); + setorigin (missile, org); + missile.velocity = dir * 800; + +}; + +void() W_FireJavelin = +{ + local vector dir; + local entity missile; + + sound (self, CHAN_WEAPON, "raven/javthrow.wav", 1, ATTN_NORM); + self.punchangle_x = -2; + + self.attack_finished = time + 0.5; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.classname = "javprojectile"; + +// set missile speed + makevectors (self.v_angle); + missile.velocity = aim(self, 1000); + missile.velocity = missile.velocity * 1000; + missile.angles = vectoangles(missile.velocity); + + missile.touch = T_MissileTouch; + +// set missile duration + missile.nextthink = time + 5; + missile.think = SUB_Remove; + + setmodel (missile, "models/javproj.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + v_forward*-14 + v_right * 16 + v_up * 32); + +}; + +/*QUAKED wp_javelin (1 0 0) (-16 -16 -24) (16 16 40) +Javelin weapon for Paladin + +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- + +*/ +void() wp_javelin = +{ + if (deathmatch) + { + remove(self); + return; + } + +}; + diff --git a/jctest.hc b/jctest.hc new file mode 100644 index 0000000..4b08c80 --- /dev/null +++ b/jctest.hc @@ -0,0 +1,22 @@ +/* + * $Header: /HexenWorld/Siege/Jctest.hc 3 5/25/98 1:39p Mgummelt $ + */ + +void() jctrig = +{ +dprint ("here\n\n"); + lightstyle(0, "az"); +}; + +/*QUAKED trigger_jctest (.5 .5 .5) ? +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +void() trigger_jctest = +{ + setsize (self, self.mins, self.maxs); + self.solid = SOLID_EDGE; + self.touch = jctrig; +}; + diff --git a/knight.hc b/knight.hc new file mode 100644 index 0000000..4afa1f3 --- /dev/null +++ b/knight.hc @@ -0,0 +1,274 @@ +/* + * $Header: /HexenWorld/Siege/Knight.hc 3 5/25/98 1:39p Mgummelt $ + */ +/* +============================================================================== + +KNIGHT + +============================================================================== +*/ + +$cd id1/models/knight +$origin 0 0 24 +$base base +$skin badass3 + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 + +$frame runb1 runb2 runb3 runb4 runb5 runb6 runb7 runb8 + +//frame runc1 runc2 runc3 runc4 runc5 runc6 + +$frame runattack1 runattack2 runattack3 runattack4 runattack5 +$frame runattack6 runattack7 runattack8 runattack9 runattack10 +$frame runattack11 + +$frame pain1 pain2 pain3 + +$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 +$frame painb10 painb11 + +//frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 +//frame attack8 attack9 attack10 attack11 + +$frame attackb1 attackb1 attackb2 attackb3 attackb4 attackb5 +$frame attackb6 attackb7 attackb8 attackb9 attackb10 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 +$frame walk10 walk11 walk12 walk13 walk14 + +$frame kneel1 kneel2 kneel3 kneel4 kneel5 + +$frame standing2 standing3 standing4 standing5 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 +$frame death9 death10 + +$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8 +$frame deathb9 deathb10 deathb11 + +void() knight_stand1 =[ $stand1, knight_stand2 ] {ai_stand();}; +void() knight_stand2 =[ $stand2, knight_stand3 ] {ai_stand();}; +void() knight_stand3 =[ $stand3, knight_stand4 ] {ai_stand();}; +void() knight_stand4 =[ $stand4, knight_stand5 ] {ai_stand();}; +void() knight_stand5 =[ $stand5, knight_stand6 ] {ai_stand();}; +void() knight_stand6 =[ $stand6, knight_stand7 ] {ai_stand();}; +void() knight_stand7 =[ $stand7, knight_stand8 ] {ai_stand();}; +void() knight_stand8 =[ $stand8, knight_stand9 ] {ai_stand();}; +void() knight_stand9 =[ $stand9, knight_stand1 ] {ai_stand();}; + +void() knight_walk1 =[ $walk1, knight_walk2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "knight/idle.wav", 1, ATTN_IDLE); +ai_walk(3);}; +void() knight_walk2 =[ $walk2, knight_walk3 ] {ai_walk(2);}; +void() knight_walk3 =[ $walk3, knight_walk4 ] {ai_walk(3);}; +void() knight_walk4 =[ $walk4, knight_walk5 ] {ai_walk(4);}; +void() knight_walk5 =[ $walk5, knight_walk6 ] {ai_walk(3);}; +void() knight_walk6 =[ $walk6, knight_walk7 ] {ai_walk(3);}; +void() knight_walk7 =[ $walk7, knight_walk8 ] {ai_walk(3);}; +void() knight_walk8 =[ $walk8, knight_walk9 ] {ai_walk(4);}; +void() knight_walk9 =[ $walk9, knight_walk10 ] {ai_walk(3);}; +void() knight_walk10 =[ $walk10, knight_walk11 ] {ai_walk(3);}; +void() knight_walk11 =[ $walk11, knight_walk12 ] {ai_walk(2);}; +void() knight_walk12 =[ $walk12, knight_walk13 ] {ai_walk(3);}; +void() knight_walk13 =[ $walk13, knight_walk14 ] {ai_walk(4);}; +void() knight_walk14 =[ $walk14, knight_walk1 ] {ai_walk(3);}; + + +void() knight_run1 =[ $runb1, knight_run2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "knight/idle.wav", 1, ATTN_IDLE); +ai_run(16);}; +void() knight_run2 =[ $runb2, knight_run3 ] {ai_run(20);}; +void() knight_run3 =[ $runb3, knight_run4 ] {ai_run(13);}; +void() knight_run4 =[ $runb4, knight_run5 ] {ai_run(7);}; +void() knight_run5 =[ $runb5, knight_run6 ] {ai_run(16);}; +void() knight_run6 =[ $runb6, knight_run7 ] {ai_run(20);}; +void() knight_run7 =[ $runb7, knight_run8 ] {ai_run(14);}; +void() knight_run8 =[ $runb8, knight_run1 ] {ai_run(6);}; + + +void() knight_runatk1 =[ $runattack1, knight_runatk2 ] +{ +if (random() > 0.5) + sound (self, CHAN_WEAPON, "knight/sword2.wav", 1, ATTN_NORM); +else + sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +ai_charge(20); +}; +void() knight_runatk2 =[ $runattack2, knight_runatk3 ] {ai_charge_side();}; +void() knight_runatk3 =[ $runattack3, knight_runatk4 ] {ai_charge_side();}; +void() knight_runatk4 =[ $runattack4, knight_runatk5 ] {ai_charge_side();}; +void() knight_runatk5 =[ $runattack5, knight_runatk6 ] {ai_melee_side();}; +void() knight_runatk6 =[ $runattack6, knight_runatk7 ] {ai_melee_side();}; +void() knight_runatk7 =[ $runattack7, knight_runatk8 ] {ai_melee_side();}; +void() knight_runatk8 =[ $runattack8, knight_runatk9 ] {ai_melee_side();}; +void() knight_runatk9 =[ $runattack9, knight_runatk10 ] {ai_melee_side();}; +void() knight_runatk10 =[ $runattack10, knight_runatk11 ] {ai_charge_side();}; +void() knight_runatk11 =[ $runattack11, knight_run1 ] {ai_charge(10);}; + +void() knight_atk1 =[ $attackb1, knight_atk2 ] +{ +sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +ai_charge(0);}; +void() knight_atk2 =[ $attackb2, knight_atk3 ] {ai_charge(7);}; +void() knight_atk3 =[ $attackb3, knight_atk4 ] {ai_charge(4);}; +void() knight_atk4 =[ $attackb4, knight_atk5 ] {ai_charge(0);}; +void() knight_atk5 =[ $attackb5, knight_atk6 ] {ai_charge(3);}; +void() knight_atk6 =[ $attackb6, knight_atk7 ] {ai_charge(4); ai_melee();}; +void() knight_atk7 =[ $attackb7, knight_atk8 ] {ai_charge(1); ai_melee();}; +void() knight_atk8 =[ $attackb8, knight_atk9 ] {ai_charge(3); +ai_melee();}; +void() knight_atk9 =[ $attackb9, knight_atk10] {ai_charge(1);}; +void() knight_atk10=[ $attackb10, knight_run1 ] {ai_charge(5);}; + +//void() knight_atk9 =[ $attack9, knight_atk10 ] {}; +//void() knight_atk10 =[ $attack10, knight_atk11 ] {}; +//void() knight_atk11 =[ $attack11, knight_run1 ] {}; + +//=========================================================================== + +void() knight_pain1 =[ $pain1, knight_pain2 ] {}; +void() knight_pain2 =[ $pain2, knight_pain3 ] {}; +void() knight_pain3 =[ $pain3, knight_run1 ] {}; + +void() knight_painb1 =[ $painb1, knight_painb2 ] {ai_painforward(0);}; +void() knight_painb2 =[ $painb2, knight_painb3 ] {ai_painforward(3);}; +void() knight_painb3 =[ $painb3, knight_painb4 ] {}; +void() knight_painb4 =[ $painb4, knight_painb5 ] {}; +void() knight_painb5 =[ $painb5, knight_painb6 ] {ai_painforward(2);}; +void() knight_painb6 =[ $painb6, knight_painb7 ] {ai_painforward(4);}; +void() knight_painb7 =[ $painb7, knight_painb8 ] {ai_painforward(2);}; +void() knight_painb8 =[ $painb8, knight_painb9 ] {ai_painforward(5);}; +void() knight_painb9 =[ $painb9, knight_painb10 ] {ai_painforward(5);}; +void() knight_painb10 =[ $painb10, knight_painb11 ] {ai_painforward(0);}; +void() knight_painb11 =[ $painb11, knight_run1 ] {}; + +void(entity attacker, float damage) knight_pain = +{ + local float r; + + if (self.pain_finished > time) + return; + + r = random(); + + sound (self, CHAN_VOICE, "knight/khurt.wav", 1, ATTN_NORM); + if (r < 0.85) + { + knight_pain1 (); + self.pain_finished = time + 1; + } + else + { + knight_painb1 (); + self.pain_finished = time + 1; + } + +}; + +//=========================================================================== + +void() knight_bow1 =[ $kneel1, knight_bow2 ] {ai_turn();}; +void() knight_bow2 =[ $kneel2, knight_bow3 ] {ai_turn();}; +void() knight_bow3 =[ $kneel3, knight_bow4 ] {ai_turn();}; +void() knight_bow4 =[ $kneel4, knight_bow5 ] {ai_turn();}; + +void() knight_bow5 =[ $kneel5, knight_bow5 ] {ai_turn();}; + +void() knight_bow6 =[ $kneel4, knight_bow7 ] {ai_turn();}; +void() knight_bow7 =[ $kneel3, knight_bow8 ] {ai_turn();}; +void() knight_bow8 =[ $kneel2, knight_bow9 ] {ai_turn();}; +void() knight_bow9 =[ $kneel1, knight_bow10 ] {ai_turn();}; +void() knight_bow10 =[ $walk1, knight_walk1 ] {ai_turn();}; + + + +void() knight_die1 =[ $death1, knight_die2 ] {}; +void() knight_die2 =[ $death2, knight_die3 ] {}; +void() knight_die3 =[ $death3, knight_die4 ] +{self.solid = SOLID_NOT;}; +void() knight_die4 =[ $death4, knight_die5 ] {}; +void() knight_die5 =[ $death5, knight_die6 ] {}; +void() knight_die6 =[ $death6, knight_die7 ] {}; +void() knight_die7 =[ $death7, knight_die8 ] {}; +void() knight_die8 =[ $death8, knight_die9 ] {}; +void() knight_die9 =[ $death9, knight_die10] {}; +void() knight_die10=[ $death10, knight_die10] {}; + + +void() knight_dieb1 =[ $deathb1, knight_dieb2 ] {}; +void() knight_dieb2 =[ $deathb2, knight_dieb3 ] {}; +void() knight_dieb3 =[ $deathb3, knight_dieb4 ] +{self.solid = SOLID_NOT;}; +void() knight_dieb4 =[ $deathb4, knight_dieb5 ] {}; +void() knight_dieb5 =[ $deathb5, knight_dieb6 ] {}; +void() knight_dieb6 =[ $deathb6, knight_dieb7 ] {}; +void() knight_dieb7 =[ $deathb7, knight_dieb8 ] {}; +void() knight_dieb8 =[ $deathb8, knight_dieb9 ] {}; +void() knight_dieb9 =[ $deathb9, knight_dieb10] {}; +void() knight_dieb10 = [ $deathb10, knight_dieb11] {}; +void() knight_dieb11 = [ $deathb11, knight_dieb11] {}; + + +void() knight_die = +{ +// check for gib + if (self.health < -40) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("progs/h_knight.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib2.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + return; + } + +// regular death + sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM); + if (random() < 0.5) + knight_die1 (); + else + knight_dieb1 (); +}; + + +/*QUAK-ED monster_knight (1 0 0) (-16 -16 -24) (16 16 40) Ambush +*/ +void() monster_knight = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/knight.mdl"); + precache_model ("progs/h_knight.mdl"); + + precache_sound ("knight/kdeath.wav"); + precache_sound ("knight/khurt.wav"); + precache_sound ("knight/ksight.wav"); + precache_sound ("knight/sword1.wav"); + precache_sound ("knight/sword2.wav"); + precache_sound ("knight/idle.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/knight.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 75; + + self.th_stand = knight_stand1; + self.th_walk = knight_walk1; + self.th_run = knight_run1; + self.th_melee = knight_atk1; + self.th_pain = knight_pain; + self.th_die = knight_die; + + walkmonster_start (); +}; + diff --git a/light.hc b/light.hc new file mode 100644 index 0000000..1eb1f34 --- /dev/null +++ b/light.hc @@ -0,0 +1,575 @@ +/* + * $Header: /HexenWorld/Siege/light.hc 7 5/25/98 1:39p Mgummelt $ + */ +/* +========================================================== +LIGHT.HC +MG + +Lights can be toggled/faded, shot out, etc. +========================================================== +*/ + +float START_LOW = 1; + +void initialize_lightstyle (void) +{ + if(self.spawnflags&START_LOW) + if(self.lightvalue1=self.fadespeed) + { + //dprint("light timed out\n"); + remove(self); + } + else if((self.cnt<0&&self.light_lev<=self.level)||(self.cnt>0&&self.light_lev>=self.level)) + { + //dprint("light fade done\n"); + lightstylestatic(self.style, self.level); + remove(self); + } + else + { + self.nextthink=time+0.05; + self.think=fadelight; + } +} + +void lightstyle_change_think() +{ + //dprint("initializing light change\n"); + self.speed=self.lightvalue2 - self.lightvalue1; + self.light_lev=lightstylevalue(self.style); + if(self.light_lev==self.lightvalue1) + self.level = self.lightvalue2; + else if(self.light_lev==self.lightvalue2) + self.level = self.lightvalue1; + else if(self.speed>0) + if(self.light_levself.fadespeed) + self.nextthink=-1; + else + self.nextthink=time+0.05; + self.think=torch_think; +} + +void torch_use (void) +{ + self.fadespeed=time+other.fadespeed+1; + torch_think(); +} + +/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_LOW NO_REMOVE +Non-displayed fading light. +Default light value is 300 +Default style is 0 +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) +NO_REMOVE = Light entity will not be removed on spawn (for banks of triggered lights,one should stick around for reference) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +void light() +{ + if (self.targetname == "") + { + remove(self); + } + else + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; +// dprintf("Targeted Light with style of %s, value of ",self.style); +// dprintf("%s\n",self.lightvalue2); + initialize_lightstyle(); +// dprintf("My lightstyle was set to: %s\n",lightstylevalue(self.style)); + remove(self); +// self.think=SUB_Remove; +// thinktime self : 1; + } +} + +/*QUAK-ED light_globe (0 1 0) (-8 -8 -8) (8 8 8) START_LOW +Sphere globe light. +Default light value is 300 +Default style is 0 +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +/* +void() light_globe = +{ + precache_model ("models/s_light.spr"); + setmodel (self, "models/s_light.spr"); + if(self.targetname) + self.use=torch_use; + self.mdl = "models/null.spr"; + self.weaponmodel = "models/s_light.spr"; + if(self.style>=32) + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; + initialize_lightstyle(); + self.think = torch_think; + self.nextthink = time+1; + } + else + { + setmodel(self,self.weaponmodel); + makestatic (self); + } +}; +*/ + +void() FireAmbient = +{ +//FIXME: remove ambient sound if light is off, start it again if turned back on + precache_sound ("raven/flame1.wav"); +// attenuate fast + ambientsound (self.origin, "raven/flame1.wav", 0.5, ATTN_STATIC); +}; + +/*QUAK-ED light_torch_small_walltorch (0 .5 0) (-10 -10 -20) (10 10 20) START_LOW +Short wall torch +Default light value is 200 +Default style is 0 +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +void() light_torch_small_walltorch = +{ + precache_model ("models/flame.mdl"); + FireAmbient (); + if(self.targetname) + self.use=torch_use; + self.mdl = "models/null.spr"; + self.weaponmodel = "models/flame.mdl"; + + self.abslight = .75; + + if(self.style>=32) + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; + initialize_lightstyle(); + self.think = torch_think; + self.nextthink = time+1; + } + else + { + self.drawflags(+)MLS_ABSLIGHT; + setmodel(self,self.weaponmodel); + makestatic (self); + } +}; + +/*QUAKED light_flame_large_yellow (0 1 0) (-10 -10 -12) (12 12 18) START_LOW +Large yellow flame +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +void() light_flame_large_yellow = +{ + precache_model ("models/flame1.mdl"); + FireAmbient (); + if(self.targetname) + self.use=torch_use; + + self.abslight = .75; + + self.mdl = "models/null.spr"; + self.weaponmodel = "models/flame1.mdl"; + if(self.style>=32) + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; + initialize_lightstyle(); + self.think = torch_think; + self.nextthink = time+1; + } + else + { + self.drawflags(+)MLS_ABSLIGHT; + setmodel(self,self.weaponmodel); + makestatic (self); + } +}; + +/*QUAKED light_flame_small_yellow (0 1 0) (-8 -8 -8) (8 8 8) START_LOW +Small yellow flame ball +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +void() light_flame_small_yellow = +{ + precache_model ("models/flame2.mdl"); + FireAmbient (); + if(self.targetname) + self.use=torch_use; + + self.abslight = .75; + + self.mdl = "models/null.spr"; + self.weaponmodel = "models/flame2.mdl"; + if(self.style>=32) + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; + initialize_lightstyle(); + self.think = torch_think; + self.nextthink = time+1; + } + else + { + self.drawflags(+)MLS_ABSLIGHT; + setmodel(self,self.weaponmodel); + makestatic (self); + } +}; + +/*QUAK-ED light_flame_small_white (0 1 0) (-10 -10 -40) (10 10 40) START_LOW +Small white flame ball +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +/* +void() light_flame_small_white = +{ + precache_model ("models/flame2.mdl"); + FireAmbient (); + if(self.targetname) + self.use=torch_use; + + self.abslight = .75; + + self.mdl = "models/null.spr"; + self.weaponmodel = "models/flame2.mdl"; + if(self.style>=32) + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; + initialize_lightstyle(); + self.think = torch_think; + self.nextthink = time+1; + } + else + { + self.drawflags(+)MLS_ABSLIGHT; + setmodel(self,self.weaponmodel); + makestatic (self); + } +}; +*/ + +/*QUAKED light_gem (0 1 0) (-8 -8 -8) (8 8 8) START_LOW +A gem that displays light. +Default light value is 300 +Default style is 0 +---------------------------------- +If triggered, will toggle between lightvalue1 and lightvalue2 +.lightvalue1 (default 0) +.lightvalue2 (default 11, equivalent to 300 brightness) +Two values the light will fade-toggle between, 0 is black, 25 is brightest, 11 is equivalent to a value of 300. +.fadespeed (default 1) = How many seconds it will take to complete the desired lighting change +The light will start on at a default of the higher light value unless you turn on the startlow flag. +START_LOW = will make the light start at the lower of the lightvalues you specify (default uses brighter) + +NOTE: IF YOU DON'T PLAN ON USING THE DEFAULTS, ALL LIGHTS IN THE BANK OF LIGHTS NEED THIS INFO +*/ +void() light_gem = +{ + precache_model ("models/gemlight.mdl"); + if(self.targetname) + self.use=torch_use; + self.mdl = "models/null.spr"; + self.weaponmodel = "models/gemlight.mdl"; + + self.abslight = .75; + + if(self.style>=32) + { + if(!self.lightvalue2) + self.lightvalue2=11; + if(!self.fadespeed) + self.fadespeed = 1; + initialize_lightstyle(); + self.think = torch_think; + self.nextthink = time+1; + } + else + { + self.drawflags(+)MLS_ABSLIGHT; + setmodel(self,self.weaponmodel); + makestatic (self); + } +}; + +void fade_down (); +void fade_up (); +void wait_fade_down () +{ + self.aflag*=-1; + self.think=fade_down; + thinktime self : self.delay; +} + +void wait_fade_up () +{ + self.aflag*=-1; + self.think=fade_up; + thinktime self : self.delay; +} + +void fade_down () +{ + self.light_lev=lightstylevalue(self.style); + if(self.light_lev==self.level) + { + if(self.spawnflags&1) + wait_fade_up(); + else + { + self.think=SUB_Null; + self.nextthink=-1; + } + return; + } + + self.think=fade_down; + thinktime self : self.wait; + + self.light_lev+=self.aflag; + if(self.light_lev<0) + self.light_lev=0; + else if(self.light_lev25) + self.light_lev=25; + else if(self.light_lev>self.lightvalue1) + self.light_lev=self.lightvalue1; + lightstylestatic(self.style, self.light_lev); +} + +/*QUAKED ambient_lightfader (.5 .5 .5) (-4 -4 -4) (4 4 4) TOGGLE +"wait" - how long to wait between fade steps (only 25 light values) + default 60 (1 minute) +"level" - what light value to stop at (from 1 - 25) + default 0 +"aflag" - direction and increment to fade at (1 is one step brighter, -1 is default-fade down 1 step) + default -1 + +TOGGLE - Will reach end of it's fade, then start fading back in/out the other way +"delay" - If toggled, how long to wait before changing fade direction and starting again. + default 300 (5 minutes) +*/ +void al_delayed_init () +{ +float savelevel; + self.use=SUB_Null; + self.lightvalue1 = lightstylevalue(self.style); + if(self.aflag>0) + { + if(self.levelself.lightvalue1) + { + savelevel = self.level; + self.level = self.lightvalue1; + self.lightvalue1=self.level; + } + self.think = fade_down; + } + thinktime self : self.wait; +} + +void ambient_lightfader () +{ +// if(!self.wait) + self.wait = 180; + if(!self.aflag) + self.aflag=-1; + if(!self.delay) + self.delay = 180; + + self.use=al_delayed_init; + self.think=al_delayed_init; + thinktime self : 180;//start fading after 3 minutes if not used first +} + diff --git a/lightning.hc b/lightning.hc new file mode 100644 index 0000000..99a3cb7 --- /dev/null +++ b/lightning.hc @@ -0,0 +1,424 @@ +/* +=============================================================================== +LIGHTNING.HC +MG + +Lightning and Sunbeam effects, and thunderstorm +=============================================================================== +*/ +void smolder_think () +{ +vector ofs; + ofs_x=random(-10,10); + ofs_y=random(-10,10); + particle(self.origin+ofs, '0 0 100', random(272,288), random(1,10)); + if(random()<0.1&&random()<0.5) + CreateWhiteSmoke(self.origin,'0 0 8',HX_FRAME_TIME * 2); + thinktime self : 0.1; + if(time>self.lifetime) + remove(self); +} + +void smolder (vector org) +{ + newmis=spawn(); + setorigin(newmis,org); + newmis.effects=EF_NODRAW; + newmis.lifetime=time+7; + newmis.think=smolder_think; + thinktime newmis : 0; +} + +void shock_think() +{ + if (self.skin ==0) + self.skin = 1; + else + self.skin = 0; + self.scale-=0.1; + + thinktime self : 0.05; + if(time>self.lifetime||self.scale<=0.1) + remove(self); +} + +void spawnshockball (vector org) +{ + newmis=spawn(); + newmis.drawflags(+)MLS_TORCH; + setmodel (newmis, "models/vorpshok.mdl"); + setorigin(newmis, org); + newmis.lifetime=time+1; + newmis.angles_z=90; + newmis.think=shock_think; + thinktime newmis : 0; + newmis.scale=2.5; +} +/* +================= +LightningDamage +================= +*/ + +void (vector endpos) ThroughWaterZap = +{ +entity waterloser, attacker; +float damg; + waterloser = spawn(); + setorigin (waterloser, endpos); + if(self.classname=="mjolnir") + damg=128; + else + damg=666*2; + attacker=self; + if(self.classname!="player") + if(self.owner.classname=="player") + attacker=self.owner; + else if(self.controller.classname=="player") + attacker=self.controller; + T_RadiusDamageWater (waterloser, self, damg,self); + remove (waterloser); +}; + +void (vector startpos) ThroughWater = +{ +vector endpos; +float mover; + mover = 600; + while (mover) + { + mover = mover - 10; + endpos = startpos + v_forward * mover; + if (pointcontents(endpos) == CONTENT_WATER || pointcontents(endpos) == CONTENT_SLIME) + ThroughWaterZap(endpos); + else if (pointcontents(endpos) == CONTENT_SOLID) + return; + } +}; + +void do_lightning_dam (entity from, float damage, string type) +{ +vector loser_org; + if((trace_ent.classname=="monster_eidolon"||trace_ent.classname=="obj_chaos_orb")&&type=="lightning") + return; + + if (type != "cubebeam") + particle (trace_endpos, '0 0 100', 225, damage*4); + if(type=="lightning") + spawnshockball((trace_ent.absmax+trace_ent.absmin)*0.5); + loser_org=trace_ent.origin; + T_Damage (trace_ent, from, from, damage); + if(trace_ent.health<=0) + smolder(loser_org); + if(type=="lightning") + sound(trace_ent,CHAN_AUTO,"misc/lighthit.wav",1,ATTN_NORM); + else if (type != "cubebeam") + sound(trace_ent,CHAN_AUTO,"crusader/sunhit.wav",1,ATTN_NORM); +} + +void(vector p1, vector p2, entity from, float damage,string type) LightningDamage = +{ +entity e1, e2;// swap; +vector f; +float inertia;//absorb; + f = p2 - p1; + normalize (f); + f_x = 0 - f_y; + f_y = f_x; + f_z = 0; + f = f*16; + + e1 = e2 = world; + + traceline (p1, p2, FALSE, self); + + if(type=="lightning"&&(pointcontents(trace_endpos) == CONTENT_WATER || pointcontents(trace_endpos) == CONTENT_SLIME)) + ThroughWaterZap(trace_endpos); + else if(type=="lightning"&&(trace_ent.watertype == CONTENT_WATER || trace_ent.watertype == CONTENT_SLIME)) + T_RadiusDamageWater (self, self, 666*2,self); + else if(self.classname=="mjolnir"&&trace_ent==self.controller) + bprint(PRINT_MEDIUM, ""); + else if (trace_ent.takedamage) + { + if (trace_ent.mass<=10) + inertia=1; + else + inertia = trace_ent.mass/10; + do_lightning_dam(from,damage,type); + if (self.classname=="mjolnir"&&(trace_ent.flags&FL_ONGROUND)&&type=="lightning") + { + trace_ent.velocity_z = trace_ent.velocity_z + 400/inertia; + trace_ent.flags(-)FL_ONGROUND; + } + } + else if(type=="lightning") + ThroughWater(p1); + + e1 = trace_ent; + traceline (p1 + f, p2 + f, FALSE, self); + if(self.classname=="mjolnir"&&trace_ent==self.controller) + bprint(PRINT_MEDIUM, ""); + else if(trace_ent != e1 && trace_ent.takedamage) + do_lightning_dam(from,damage,type); + + e2 = trace_ent; + traceline (p1 - f, p2 - f, FALSE, self); + if(self.classname=="mjolnir"&&trace_ent==self.controller) + bprint(PRINT_MEDIUM, ""); + else if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage) + do_lightning_dam(from,damage,type); +}; + +void do_lightning (entity lowner,float tag, float lflags, float duration, vector spot1, vector spot2, float ldamg,float te_type) +{ +vector damage_dir; + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, te_type); + WriteEntity (MSG_BROADCAST, lowner); + WriteByte (MSG_BROADCAST, tag+lflags); + WriteByte (MSG_BROADCAST, duration); + + WriteCoord (MSG_BROADCAST, spot1_x); + WriteCoord (MSG_BROADCAST, spot1_y); + WriteCoord (MSG_BROADCAST, spot1_z); + + WriteCoord (MSG_BROADCAST, spot2_x); + WriteCoord (MSG_BROADCAST, spot2_y); + WriteCoord (MSG_BROADCAST, spot2_z); + + if(ldamg) + { + if(self.owner.classname=="player") + lowner=self.owner; + else if(self.controller.classname=="player") + lowner=self.controller; + + damage_dir=normalize(spot2-spot1); + LightningDamage (spot1-damage_dir*15, spot2+damage_dir*15, lowner, ldamg,"lightning"); + } +} + +void(float max_strikes, float damg) CastLightning = +{ +//Not working, I want 3 seperate beams, when get that, drop damage to 10 +vector org, dir,tospot; +float number_strikes; + + self.effects(+)EF_MUZZLEFLASH; + + if(max_strikes==0) + max_strikes=1; + while(max_strikes>number_strikes) + { + if(random()<0.7) + sound(self.enemy,CHAN_AUTO,"crusader/lghtn1.wav",1,ATTN_NORM); + else + sound(self.enemy,CHAN_AUTO,"crusader/lghtn2.wav",1,ATTN_NORM); + if(self.enemy.solid==SOLID_BSP&&self.enemy.origin=='0 0 0') + org=(self.enemy.absmin+self.enemy.absmax)*0.5; + else + { + org=self.enemy.origin; + org_z += 0.5*self.enemy.maxs_z; + } + dir=org; + dir_x+= random(-300,300); + dir_y+= random(-300,300); + dir_z+= 500; + traceline(org,dir,TRUE,self); + tospot=org; + org=trace_endpos; + do_lightning (self,number_strikes,0,4,org,tospot,damg,TE_STREAM_LIGHTNING); + number_strikes+=1; + } +}; + +void()rolling_thunder; +void thunder_clear () +{ + self.owner.aflag-=1; + remove(self); +} + +void thunder_sound () +{ +float sound_vol; + sound_vol=self.lightvalue2/25; + if(sound_vol>1) + sound_vol=1; + else if(sound_vol<0) + sound_vol=0.1; + sound (self, CHAN_VOICE, "ambience/thunder1.wav", sound_vol, ATTN_NORM); + thinktime self : 5; + self.think=thunder_clear; +} + +void spawn_thunder () +{ + self.aflag+=1; + newmis=spawn(); + self.angles_y=random(360); + makevectors(self.angles); + setorigin(newmis,self.origin+v_forward*self.lightvalue2*10); + newmis.owner=self; + newmis.lightvalue2=self.lightvalue2; + newmis.think=thunder_sound; + thinktime newmis : 2.5 - self.lightvalue2/10; +} + +void flash_wait () +{ + lightstylestatic(self.style,self.lightvalue1); + self.think=rolling_thunder; + thinktime self : 0; +} + +void lightning_strike (void) +{ +vector org,tospot, lightn_dir; +float dist, num_branches; + dist=random(self.frags); + self.angles_y=random(360); + makevectors(self.angles); + traceline(self.origin,self.origin+v_forward*dist,TRUE,self); + org=trace_endpos; + tospot=org-'0 0 1000'; + traceline(org,tospot,TRUE,self); + tospot=trace_endpos; + tospot_x+=random(-100,100); + tospot_y+=random(-100,100); + dist=vlen(tospot-org); + + newmis=spawn(); + setorigin(newmis,org); + if(random()<0.5) + sound(newmis,CHAN_AUTO,"crusader/lghtn1.wav",1,ATTN_NORM); + else + sound(newmis,CHAN_AUTO,"crusader/lghtn2.wav",1,ATTN_NORM); + newmis.think=SUB_Remove; + thinktime newmis : 3; + + num_branches = rint(random(3,7)); + while(num_branches) + { + self.level+=1; + if(self.level>=8) + self.level=0; + + if (self.lockentity.classname == "monster_buddha") + do_lightning (self.lockentity,self.level,STREAM_ATTACHED,4,org,tospot,50,TE_STREAM_LIGHTNING); + else + do_lightning (self,self.level,STREAM_ATTACHED,4,org,tospot,10000,TE_STREAM_LIGHTNING); + + lightn_dir=normalize(tospot-org); + org=org + lightn_dir*random(num_branches+dist/10,num_branches+dist/5);//Include trace_fraction? + tospot=org-'0 0 1000'; + traceline(trace_endpos,tospot,TRUE,self); + tospot=trace_endpos; + if(random()<0.5) + tospot_x+=random(125,375); + else + tospot_x-=random(125,375); + if(random()<0.5) + tospot_y+=random(125,375); + else + tospot_y-=random(125,375); + + /*if(trace_fraction<0.01) + { + dprint("not into ground\n"); + num_branches=0; + } + else*/ + num_branches-=1; + } +} + +void rolling_thunder (void) +{ + if(random(100)>=self.wait) + { + if(self.spawnflags&1&&random(100)=8) + self.count=0; + + do_lightning2 (self,self.count,STREAM_ATTACHED,4,org,tospot,30); + + lightn_dir=normalize(tospot-org); + org=org + lightn_dir*random(num_branches+20,num_branches+45);//Include trace_fraction? + tospot=org+v_forward*1000; + traceline(trace_endpos,tospot,TRUE,self); + tospot=trace_endpos; + if(random()<0.5) + tospot+=v_right*random(150,400); + else + tospot-=v_right*random(150,400); + if(random()<0.5) + tospot+=v_up*random(150,400); + else + tospot-=v_up*random(150,400); + + num_branches-=1; + } +} + +void shebitch_chain_lightning_strike () +{ + vector org, tospot; + float damg,damg_thresh, zap_count,fov_check; + entity loser, lastloser,firstloser; + float numTargs; + + numTargs = 0; + + if(self.attack_finished>time) + return; + self.greenmana-=4; + self.bluemana-=4; + self.attack_finished=time+0.2; + self.effects(+)EF_MUZZLEFLASH; + makevectors(self.v_angle); + org=self.origin+self.proj_ofs+v_forward*36; + + loser=findradius(org,1000); + firstloser=lastloser=loser; + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_CHAINLIGHTNING); + WriteEntity(MSG_MULTICAST, self); + + WriteCoord(MSG_MULTICAST, org_x); + WriteCoord(MSG_MULTICAST, org_y); + WriteCoord(MSG_MULTICAST, org_z); + + while((loser!=world)&&(numTargs < 5)) + { + if(loser.health&&loser.flags2&FL_ALIVE&&loser!=self) + { + tospot=(loser.absmin+loser.absmax)*0.5; + traceline(org,tospot,TRUE,self); + if(infront(loser)) + { + if(lastloser==firstloser) + { + fov_check=vlen(loser.origin-self.origin); + fov_check=(50/fov_check); + if(fov_check>1) + fov_check=1; + fov_check*=10;//at further distances, cone is smaller + if(!fov(loser,self,fov_check)) + trace_fraction=0; + } + } + else + trace_fraction=0; + + if(trace_fraction==1) + { + if(loser.flags&FL_MONSTER) + damg_thresh=40; + else + damg_thresh=random(15,25); + if(loser.health>damg_thresh) + damg=damg_thresh; + else + damg=1000; + self.count+=1; + if(self.count>=8) + self.count=0; + tospot=(loser.absmin+loser.absmax)*0.5; + zap_count+=1; + + do_lightning2 (self,self.count,STREAM_ATTACHED,4,org,tospot,damg); + numTargs += 1; // ensure that there are fewer than 5 targets hit... + org=tospot; + if(lastloser==self) + firstloser=loser; + lastloser=loser; + } + } + loser=loser.chain; + } + + if(!zap_count) + { + branch_fire(org); + + traceline(org, org + v_forward * 128, TRUE, self); + + WriteCoord(MSG_MULTICAST, org_x + v_forward_x * 128 * trace_fraction); + WriteCoord(MSG_MULTICAST, org_y + v_forward_y * 128 * trace_fraction); + WriteCoord(MSG_MULTICAST, org_z + v_forward_z * 128 * trace_fraction); + + } + + WriteCoord(MSG_MULTICAST, 0); + WriteCoord(MSG_MULTICAST, 0); + WriteCoord(MSG_MULTICAST, 0); + multicast(self.origin,MULTICAST_PVS); +} + + +void()lightning_ready_power; +void()lightning_ready_normal; +void lightning_fire_normal (void) +{ + if(self.weaponframe_cnt) + self.wfs = advanceweaponframe($fidle1,$fidle16); + else + { + self.wfs = advanceweaponframe($normal1,$normal16); + if(self.weaponframe==$normal2) + { + if(self.effects&EF_DIMLIGHT) + self.lefty=TRUE; + else + self.effects(+)EF_DIMLIGHT; + } + else if(self.weaponframe==$normal16) + { + if(!self.lefty) + self.effects(-)EF_DIMLIGHT; + else + self.lefty=FALSE; + } + } + self.th_weapon=lightning_fire_normal; + self.last_attack=time; + if(self.artifact_active&ART_TOMEOFPOWER) + { + if(self.effects&EF_DIMLIGHT) + { + if(!self.lefty) + self.effects(-)EF_DIMLIGHT; + else + self.lefty=FALSE; + } + lightning_ready_power(); + } + else if(self.greenmana<6|| + self.bluemana<6|| + (!self.button0&&self.weaponframe==$normal16) + ) + { + if(self.effects&EF_DIMLIGHT) + { + if(!self.lefty) + self.effects(-)EF_DIMLIGHT; + else + self.lefty=FALSE; + } + lightning_ready_normal(); + } + else if(self.weaponframe==$normal12 ||(self.weaponframe>=$fidle1 &&self.weaponframe<=$fidle16)) + { + if(self.attack_finishedtime) + return; + + FireFlash(); + FireMagicMissile(-3); + FireMagicMissile(0); + FireMagicMissile(3); + self.greenmana-=10; + self.attack_finished=time+0.7; +} + +void mmis_normal() +{ + if(self.attack_finished>time) + return; + + FireFlash(); + FireMagicMissile(0); + self.greenmana-=2; + self.attack_finished=time+0.3; +} + +/*====================== +ACTION +select +deselect +ready loop +relax loop +fire once +fire loop +ready to relax(after short delay) +relax to ready(Fire delay? or automatic if see someone?) +=======================*/ + + +void()magicmis_ready; +void() Nec_Mis_Attack; + +void magicmis_fire (void) +{ + if(self.button0&&self.weaponframe==$mfire5 &&!self.artifact_active&ART_TOMEOFPOWER) + self.weaponframe=$mfire5; + else + self.wfs = advanceweaponframe($mfire1,$mfire8); + self.th_weapon=magicmis_fire; + self.last_attack=time; + if(self.wfs==WF_CYCLE_WRAPPED||self.greenmana<2)//||(self.artifact_active&ART_TOMEOFPOWER&&self.bluemana<10)) + magicmis_ready(); + else if(self.weaponframe==$mfire5)// &&self.attack_finished<=time) +// if(self.artifact_active&ART_TOMEOFPOWER) +// mmis_power(); +// else + mmis_normal(); +} + +void() Nec_Mis_Attack = +{ + magicmis_fire(); + + thinktime self : 0; +}; + +void magicmis_jellyfingers () +{ + self.wfs = advanceweaponframe($midle01,$midle22); + self.th_weapon=magicmis_jellyfingers; + if(self.wfs==WF_CYCLE_WRAPPED) + magicmis_ready(); +} + +void magicmis_ready (void) +{ + self.weaponframe=$midle01; + if(random()<0.1&&random()<0.3&&random()<0.5) + self.th_weapon=magicmis_jellyfingers; + else + self.th_weapon=magicmis_ready; +} + + +void magicmis_select (void) +{ + self.wfs = advanceweaponframe($mselect01,$mselect20); + self.weaponmodel = "models/spllbook.mdl"; + self.th_weapon=magicmis_select; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + magicmis_ready(); + } +} + +void magicmis_deselect (void) +{ + self.wfs = advanceweaponframe($mselect20,$mselect01); + self.th_weapon=magicmis_deselect; + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + +void magicmis_select_from_bone (void) +{ + self.wfs = advanceweaponframe($go2mag01,$go2mag13); + self.weaponmodel = "models/spllbook.mdl"; + self.th_weapon=magicmis_select_from_bone; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + magicmis_ready(); + } +} + diff --git a/math.hc b/math.hc new file mode 100644 index 0000000..5e6faa4 --- /dev/null +++ b/math.hc @@ -0,0 +1,79 @@ +/* + * $Header: /HexenWorld/Siege/math.hc 3 5/25/98 1:39p Mgummelt $ + */ + + + +/* + * crandom() -- Returns a random number between -1 and 1. + */ + +float crandom() +{ + return random(-1,1); +} + +float fexp(float base,float exponent) +{//MG +float exp_count; + + exponent=rint(exponent); + if(exponent==0) + return 1; + if(exponent<0) + { + base=1/base; + exponent=fabs(exponent); + } + + if(exponent==1) + return base; + + exponent-=1; + while(exp_count=$swipe6 &&self.frame<=$swipe10) + { + makevectors(self.angles); + traceline(self.origin+'0 0 23',self.origin+'0 0 23'-v_forward*72+v_right*($swipe7 - self.frame)*10,FALSE,self); + if(trace_ent.takedamage) + { + T_Damage(trace_ent,self,self,7); + sound(trace_ent,CHAN_BODY,"weapons/met2flsh.wav",1,ATTN_NORM); + SpawnPuff(trace_endpos,'0 0 0',7,trace_ent); + trace_ent.velocity+=v_right*-200; + trace_ent.velocity_z+=100; + trace_ent.flags(-)FL_ONGROUND; + } + } + else if(self.frame>$swipe10) + ai_face(); +} + +float MedusaCheckAttack (void) +{ +vector org,dir,destiny; +float r, loscheck1,loscheck2; + if(random()<0.5 - skill/10 - self.skin/5||self.enemy==world) + return FALSE; + + org=self.origin+self.view_ofs; + + if (time < self.attack_finished) + return FALSE; + + if (!enemy_vis) + { + if(self.goalentity.classname=="waypoint") + { + if(visible2ent(self.enemy,self.goalentity)) + { + MedusaSelectDir(MEDUSA_SNAKES); + return TRUE; + } + } + return FALSE; + } + + if(!enemy_infront) + { + if(enemy_range==RANGE_MELEE) + { + MedusaSwipe(); + return TRUE; + } + } + + if (enemy_range == RANGE_FAR) + { + if (self.attack_state != AS_STRAIGHT) + self.attack_state = AS_STRAIGHT; + return FALSE; + } + +// see if any entities are in the way of the shot + dir = self.enemy.origin + self.enemy.view_ofs; + + traceline (org, dir, FALSE, self); + if (trace_ent != self.enemy) + { // don't have a clear shot, so move to a side + if (self.attack_state != AS_SLIDING) + self.attack_state == AS_SLIDING; + return FALSE; + } + else + self.attack_state == AS_STRAIGHT; + + destiny = self.enemy.origin+self.enemy.view_ofs; +//FIXME: account for z difference + loscheck1=lineofsight(self.enemy,self); + loscheck2=lineofsight(self,self.enemy); + r=random(); + + if(!self.enemy.artifact_active&ARTFLAG_STONED&&loscheck1&& (loscheck2|| (r<0.1&&infront_of_ent(self,self.enemy)) ) ) + { + MedusaGaze(org,destiny,self.enemy); + return TRUE; + } + + if (enemy_range == RANGE_MELEE) + { + MedusaSelectDir(MEDUSA_HEADBUTT); + return TRUE; + } + else if (enemy_range == RANGE_NEAR) + r = 0.2; + else if (enemy_range == RANGE_MID) + r = 0.3; + + if (random () < r) + { + MedusaSelectDir(MEDUSA_SNAKES); + return TRUE; + } + return FALSE; +} + +//==================================================================== +void()medusa_look_right; +void MedusaHeadTouch () +{ + if(self.velocity!='0 0 0'&&!other.flags2&FL_ALIVE) + sound(self,CHAN_AUTO,"weapons/hithurt2.wav",1,ATTN_NORM); +} + +void()MedusaHeadDying; +void MedusaHeadDead () [++ 0 .. 45] +{ + thinktime self : 0.1; + ai_face(); + if(self.frame==20) + sound(self,CHAN_VOICE,"medusa/sight.wav",0.5,ATTN_NORM); + else if(self.frame==45) + { + self.aflag=TRUE; + self.think=MedusaHeadDying; + } +} + +void MedusaHeadDying () [++ 46 .. 105] +{ + if(pointcontents(self.origin)==CONTENT_SOLID) + { + chunk_death(); + return; + } + + if(self.velocity=='0 0 0') + if(!self.aflag) + { + if(self.angles_x<-10||self.angles_x>10) + self.angles_x=0; + if(self.angles_z<-10||self.angles_z>10) + self.angles_z=0; + self.solid = SOLID_BBOX; + self.think=MedusaHeadDead; + thinktime self : 0; + } + else if(self.frame==105) + { + self.skin=1; + self.think=init_corpseblink; + thinktime self : 5; + } +} + +void MedusaThrowHead () +{ + newmis = spawn(); + newmis.owner=self; + newmis.enemy=newmis.goalentity=self.enemy; + newmis.yaw_speed=3; + setmodel (newmis, self.headmodel); + self.headmodel=""; + setsize (newmis, '-3 -3 -3', '3 3 3'); + setorigin(newmis,self.absmax - '0 0 15'); + newmis.velocity = randomv('-200 -200 200','200 200 600'); + newmis.movetype = MOVETYPE_BOUNCE; + if(pointcontents(newmis.origin)==CONTENT_SOLID) + newmis.solid = SOLID_NOT; + else + newmis.solid = SOLID_BBOX; + newmis.takedamage=DAMAGE_YES; + newmis.thingtype=self.thingtype; + newmis.th_die=chunk_death; + newmis.touch=MedusaHeadTouch; + newmis.health=25; + newmis.scale=2; + + newmis.avelocity_x = random(600); + newmis.avelocity_y = random(600); + newmis.avelocity_z = random(600); + newmis.think=MedusaHeadDying; + thinktime newmis : 0; +} + +void medusa_decap_drop ()[++ $bdecap1 .. $bdecap25] +{ + if(self.frame==$bdecap9) + sound(self,CHAN_BODY,"player/land.wav",1,ATTN_NORM); + else if(self.frame==$bdecap25) + MakeSolidCorpse(); +} + +void medusa_decap_loop ()[++ $adecap1..$adecap88] +{ + if(random()<0.5) + self.angles_y+=random(-3,3); + walkmove(self.angles_y,self.speed*random(),FALSE); + + if(random()<0.2) + { + sound (self, CHAN_VOICE, "misc/decomp.wav", 0.3, ATTN_NORM); + SpawnPuff (self.origin+'0 0 56', '0 0 35',5,self); + } + + if(self.frame==$adecap48) + sound(self,CHAN_BODY,"medusa/rattle.wav",1,ATTN_NORM); + if(cycle_wrapped) + { + self.think=medusa_decap_drop; + thinktime self : 0; + } +} + +void medusa_decap_init () +{ +float throwdist; + throwdist=self.health; + ThrowGib("models/medsnake.mdl",throwdist); + ThrowGib("models/medsnake.mdl",throwdist); + ThrowGib("models/medsnake.mdl",throwdist); + sound(self,CHAN_VOICE,"player/gib2.wav",1,ATTN_NORM); + MedusaThrowHead(); + SpawnPuff (self.origin+'0 0 56', '0 0 35',5,self); + medusa_decap_loop(); +} + +void medusa_die (void) [++ $death01..$death20] +{ + medusa_check_use_model("models/medusa2.mdl"); + if(self.decap) + medusa_decap_init(); + else if(self.health<=-80) + { + MedusaThrowHead(); + chunk_death(); + } + else + { + if(self.frame==$death20) + MakeSolidCorpse(); + else if(self.frame==$death01) + sound(self,CHAN_VOICE,"medusa/death.wav",1,ATTN_NORM); + } +} + +void medusa_pain_anim () [++ $pain1 .. $pain11] +{ +//sound + medusa_check_use_model("models/medusa2.mdl"); + if (cycle_wrapped) + { + thinktime self : 0; + self.think=self.th_run; + } + else if(self.frame==$pain1) + sound(self,CHAN_VOICE,"medusa/pain.wav",1,ATTN_NORM); +} + +void medusa_pain (entity attacker,float total_damage) +{ + if(random()<0.6&&total_damage<50&&attacker!=self) + return; + + medusa_pain_anim(); +} + +void()medusa_look_left = [++ $looklf1 .. $looklf29] +{ + medusa_check_use_model("models/medusa.mdl"); + if(self.oldthink==self.th_run) + ai_run(self.speed); + else + { + if(self.oldthink==self.th_stand) + ai_stand(); + else if(self.oldthink==self.th_walk) + ai_walk(5); + } + if(cycle_wrapped) + { + self.think=self.oldthink; + if(self.think!=self.th_run) + if(random()<0.2) + self.think=medusa_look_right; + thinktime self : 0; + } +}; + +void()medusa_look_right = [++ $lookrt1 .. $lookrt29] +{ + medusa_check_use_model("models/medusa.mdl"); + if(self.oldthink==self.th_run) + ai_run(self.speed); + else + { + if(self.oldthink==self.th_stand) + ai_stand(); + else if(self.oldthink==self.th_walk) + ai_walk(5); + } + if(cycle_wrapped) + { + self.think=self.oldthink; + if(self.think!=self.th_run) + if(random()<0.2) + self.think=medusa_look_left; + thinktime self : 0; + } +}; + +void()medusa_rattle_left = [++ $ratlft1 .. $ratlft29] +{ +//sound + medusa_check_use_model("models/medusa.mdl"); + if(cycle_wrapped) + { + thinktime self : 0; + self.think=self.th_run; + } +}; + +void()medusa_rattle_right = [++ $ratrit1 .. $ratrit29] +{ +//sound + medusa_check_use_model("models/medusa.mdl"); + if(cycle_wrapped) + { + thinktime self : 0; + self.think=self.th_run; + } +}; + +void()medusa_rattle = [++ $ratatt1 .. $ratatt29] +{ +//sound + medusa_check_use_model("models/medusa.mdl"); + if(cycle_wrapped) + { + thinktime self : 0; + self.think=self.th_run; + } +}; + +void MedusaSelectDir (float action) +{ +vector enemy_dir; +float dot; + medusa_check_use_model("models/medusa.mdl"); + self.monster_stage=action; + if(action>=MEDUSA_HEADBUTT) + { + self.last_attack=time; + sound (self,CHAN_VOICE,"medusa/hiss.wav",1,ATTN_NORM); + medusa_check_use_model("models/medusa2.mdl"); + } + else if(action==MEDUSA_RATTLE) + sound(self,CHAN_BODY,"medusa/rattle.wav",1,ATTN_NORM); + makevectors(self.angles); + enemy_dir=normalize(self.enemy.origin-self.origin); + dot=v_right*enemy_dir; + if(dot>0.3) + { + self.angle_ofs_y=-90; + if(action>=MEDUSA_HEADBUTT) + self.think=medusa_attack_right; + else if(action==MEDUSA_RATTLE) + self.think=medusa_rattle_right; + else + self.think=medusa_look_right; + } + else if(dot<-0.3) + { + self.angle_ofs_y=-90; + if(action>=MEDUSA_HEADBUTT) + self.think=medusa_attack_left; + else if(action==MEDUSA_RATTLE) + self.think=medusa_rattle_left; + else + self.think=medusa_look_left; + } + else + { + self.angle_ofs_y=0; + if(action>=MEDUSA_HEADBUTT) + self.think=medusa_attack; + else if(action==MEDUSA_RATTLE) + self.think=medusa_rattle; + else + return; + } + thinktime self : 0; +} + +void medusa_hunt () [++ $medusa1 .. $medusa29] +{ + medusa_check_use_model("models/medusa.mdl"); + + if(random()<0.1) + ai_run(0); + else + ai_run(self.speed); + + if(!enemy_vis) + if(random()<0.1&&random()<0.5) + if(random()<0.5) + MedusaSelectDir(MEDUSA_RATTLE); + else + { + self.oldthink=self.th_run; + MedusaSelectDir(MEDUSA_LOOK); + } +} + +void medusa_walk () [++ $medusa1 .. $medusa29] +{ + medusa_check_use_model("models/medusa.mdl"); + self.monster_awake=FALSE; + if(random()<0.1) + ai_walk(0); + else + ai_walk(5); + if(cycle_wrapped) + { + if(random()<0.3) + { + self.oldthink=self.th_walk; + if(random()<0.5) + { + thinktime self : 0; + self.think=medusa_look_left; + } + else + { + thinktime self : 0; + self.think=medusa_look_right; + } + } + } +// MedusaCheckAttack(); + if(random()<0.1&&random()<0.5) + sound(self,CHAN_VOICE,"medusa/hiss.wav",1,ATTN_NORM); +} + +void medusa_stand () [++$stand1..$stand29] +{ + medusa_check_use_model("models/medusa.mdl"); + self.monster_awake=FALSE; + ai_stand(); + if(random()<0.1) + { + self.oldthink=self.th_stand; + if(random()<0.5) + { + thinktime self : 0; + self.think=medusa_look_left; + } + else + { + thinktime self : 0; + self.think=medusa_look_right; + } + } + if(random()<0.1&&random()<0.3) + sound(self,CHAN_VOICE,"medusa/hiss.wav",1,ATTN_NORM); +} + + +/*QUAKED monster_medusa_green (1 0.3 0) (-16 -16 0) (16 16 56) AMBUSH STUCK JUMP PLAY_DEAD DORMANT + +The medusa monster with its nasty sharp pointy teeth +-------------------------FIELDS------------------------- +-------------------------------------------------------- +*/ +void monster_medusa_green (void) +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model2("models/medusa.mdl"); + precache_model2("models/medusa2.mdl"); + precache_model2("models/snakearr.mdl"); + precache_model2("models/medhit.spr"); + precache_model2("models/medhead.mdl"); + precache_model2("models/medsnake.mdl"); + precache_sound2("medusa/rattle.wav"); + precache_sound2("medusa/hiss.wav"); + precache_sound2("medusa/sight.wav"); + precache_sound2("medusa/attack1.wav"); + precache_sound2("medusa/attack2.wav"); + precache_sound2("medusa/pain.wav"); + precache_sound2("medusa/death.wav"); + precache_sound2("medusa/stoned.wav"); + precache_sound2("medusa/hitplayr.wav"); + +// if(random()<0.5) +// self.skin=1; + + self.headmodel="models/medhead.mdl"; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.takedamage=DAMAGE_YES; + self.thingtype=THINGTYPE_FLESH; + self.monsterclass=CLASS_LEADER; + self.mintel = 20;//Very smart- excellent tracker + self.mass = 15; + self.view_ofs = '0 0 53'; + self.speed=5; + self.yaw_speed = 5; + self.classname="monster_medusa"; + self.health = 700; + self.experience_value = 500; + + self.th_stand=medusa_stand; + self.th_run=medusa_hunt; + self.th_walk=medusa_walk; + self.th_die=medusa_die; + self.th_pain=medusa_pain; + self.th_missile=medusa_rattle; + self.th_melee=medusa_attack; + + setmodel (self, "models/medusa.mdl"); + + setsize(self, '-28 -28 0', '28 28 56'); + self.hull=HULL_PLAYER; + + walkmonster_start(); +} + +void monster_medusa (void) +{ + monster_medusa_green(); +} + +/*QUAKED monster_medusa_red (1 0.3 0) (-16 -16 0) (16 16 56) AMBUSH STUCK JUMP PLAY_DEAD DORMANT + +The medusa monster with its nasty sharp pointy teeth +-------------------------FIELDS------------------------- +-------------------------------------------------------- +*/ +void monster_medusa_red (void) +{ +// self.skin=1; + monster_medusa_green(); + self.health = 250; + self.experience_value = 125; +} diff --git a/medusa2.hc b/medusa2.hc new file mode 100644 index 0000000..e69de29 diff --git a/messages.hc b/messages.hc new file mode 100644 index 0000000..db4129c --- /dev/null +++ b/messages.hc @@ -0,0 +1,10 @@ +/* + * $Header: /HexenWorld/Siege/messages.hc 3 5/25/98 1:39p Mgummelt $ + */ + +void () message_init = +{ + + time = time; +}; + diff --git a/meteor.hc b/meteor.hc new file mode 100644 index 0000000..1683b1d --- /dev/null +++ b/meteor.hc @@ -0,0 +1,451 @@ +/* + * $Header: /HexenWorld/Siege/meteor.hc 34 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\meteor\final\meteor.hc + +============================================================================== +*/ +// For building the model +$cd Q:\art\models\weapons\meteor\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame idle + +// +$frame Select1 Select2 Select3 Select4 Select5 +$frame Select6 Select7 Select8 Select9 Select10 +$frame Select11 Select12 Select13 Select14 Select15 +$frame Select16 Select17 Select18 + +// +$frame fire1 fire2 fire3 fire4 fire5 +$frame fire6 fire7 fire8 fire9 + + +void MeteoriteFizzle (void) +{ + CreateWhiteSmoke(self.origin,'0 0 8',HX_FRAME_TIME * 2); + remove(self); +} + +void ByeByeMeteor(void) +{ + remove(self); +} + +void MeteorExplode(void) +{ + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_METEORHIT); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 8); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 8); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 8); + multicast(self.origin,MULTICAST_PHS_R); + + T_RadiusDamage (self, self.owner, 80.0, world); + + remove(self); +} + +void MeteorTouch (void) +{ + if(other.controller==self.owner) + return; + + if(other.takedamage&&other.health) + { + T_Damage(other,self,self.owner,self.dmg); + + if((other.flags&FL_CLIENT||other.flags&FL_MONSTER)&&other.mass<200) + { + vector hitdir; + hitdir=self.o_angle*300; + hitdir_z+=150; + if(hitdir_z<0) + hitdir_z=0; + other.velocity=hitdir; + other.flags(-)FL_ONGROUND; + } + } + self.dmg=90; + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_METEORHIT); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 8); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 8); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 8); + multicast(self.origin,MULTICAST_PHS_R); + + T_RadiusDamage (self, self.owner, self.dmg, other); + + remove(self); +} + +void MeteorThink(void) +{ + self.movedir = normalize(self.velocity); + + self.angles = vectoangles(self.movedir); + + traceline(self.origin, self.origin + self.movedir * 300.0, FALSE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_METEOR); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 100); + multicast(self.origin,MULTICAST_PVS); + + thinktime self : 0.3; + + if (self.lifetime < time) + SUB_Remove(); + +} + + +void FireMeteor (string type) +{ + vector org; + entity meteor; + + meteor=spawn(); + setmodel(meteor,"models/tempmetr.mdl"); + + meteor.th_die=MultiExplode; + meteor.takedamage = DAMAGE_NO; + meteor.health = 9999; + if(self.classname=="player") + { + self.greenmana-=8; + self.velocity+=normalize(v_forward)*-300;//include mass + self.flags(-)FL_ONGROUND; + } + meteor.classname="meteor"; + self.punchangle_x = -6; + weapon_sound(self, "crusader/metfire.wav"); + self.attack_finished=time + 0.7; + self.effects(+)EF_MUZZLEFLASH; + makevectors(self.v_angle); + meteor.speed=1000; + meteor.o_angle=normalize(v_forward); + meteor.velocity=meteor.o_angle*meteor.speed; + meteor.veer=30; + meteor.lifetime=time + 5; + meteor.dmg=65; + meteor.movetype=MOVETYPE_FLYMISSILE; + org=self.origin+self.proj_ofs+v_forward*12; + setsize(meteor,'0 0 0', '0 0 0'); + meteor.movedir = normalize(meteor.velocity); + meteor.effects(+)EF_NODRAW; + + meteor.drawflags(+)MLS_FIREFLICKER;//|MLS_ABSLIGHT; + + + if(self.classname=="tornato") + meteor.owner=self.controller; + else if(self.classname=="meteor") + meteor.owner=self.owner; + else + meteor.owner=self; + meteor.controller=self; + + meteor.solid=SOLID_BBOX; + meteor.touch=MeteorTouch; + + setorigin(meteor,org); + + entity oldself; + oldself = self; + self = meteor; + + meteor.think = MeteorThink; + meteor.think(); + + self = oldself; + +} + +void MegaMeteorIgnite(void) +{ + float i; + vector startPos, endPos; + entity hurtGuy; + + if(self.health == 6) + { // must've timed out or been in-air ignited... + self.health = 5; + } + + if(self.health == 5) + { + traceline(self.origin, self.origin + '0 0 -2000', FALSE, self); + + // only make meteors on the first frame + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_METEOR_CRUSH); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 8); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 8); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 8); + WriteLong (MSG_MULTICAST, 2000 * trace_fraction); + multicast(self.origin,MULTICAST_PHS_R); + + self.effects (+) EF_NODRAW; + self.think = MegaMeteorIgnite; + + self.velocity_x = 0; + self.velocity_y = 0; + self.velocity_z = 0; + } + + i = 6; + + while(i > 0) + { + startPos = self.origin; + startPos_x += random(-80, 80); + startPos_y += random(-80, 80); + + endPos = startPos; + endPos_x += random(-90, 90)*4; + endPos_y += random(-90, 90)*4; + endPos_z += random(-1800, -1600)*4; + + // simulate the meteor going through the air; simulate the meteor's width + traceline (startPos, endPos, FALSE, self.owner); + +// if(trace_ent.takedamage) +// { +// T_Damage (trace_ent, self, self.owner, 40); +// } + hurtGuy=findradius(trace_endpos,90); + while(hurtGuy) + { + T_Damage(hurtGuy, self, self, 50 * (1.0 - (vlen(hurtGuy.origin - trace_endpos)/90))); + hurtGuy=hurtGuy.chain; + } + + i-=1; + } + + self.health -= 1; + if(self.health == 0) + { + remove(self); + } + else + { + self.nextthink = time + 0.05; + } +} + +void MegaMeteorTouch(void) +{ + if(other == self.owner) + { + return; + } + + if((other != world)&&(self.health != 6)) + { + return; + } + + if(self.health == 6) + { + self.health = 5; + self.velocity_x = 0; + self.velocity_y = 0; + self.velocity_z = 1600; + self.lifetime = time + 0.5; + self.flags(-)FL_ONGROUND; + } + else + { + MegaMeteorIgnite(); + } + +} + +void MegaMeteorThink(void) +{ + if(self.lifetime < time) + { + self.health = 5; + MegaMeteorIgnite(); + return; + //self.health = 5; + } + +/* if((self.owner.button0)&&(self.lifetime - time < 4.7)) + { // if the owner tries firing again and the projectile's been around for at least .3 of a second... + self.health = 5; + }*/ + + if(self.health == 5) + { + self.velocity_x = 0; + self.velocity_y = 0; + self.velocity_z = 1600; + self.flags(-)FL_ONGROUND; + } + + self.movedir = normalize(self.velocity); + + self.angles = vectoangles(self.movedir); + + traceline(self.origin, self.origin + self.velocity*.3, TRUE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_MEGAMETEOR); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 100); + multicast(self.origin,MULTICAST_PVS); + + thinktime self : 0.3; + +} + +void FireMeteorTornado(void) +{ + vector org; + entity meteor; + + meteor=spawn(); + setmodel(meteor,"models/tempmetr.mdl"); + meteor.scale = 2.3; + + if(self.classname=="player") + { + self.greenmana-=16; + self.velocity+=normalize(v_forward)*-100;//include mass + self.flags(-)FL_ONGROUND; + } + + meteor.classname="meteor"; + self.punchangle_x = -6; + weapon_sound(self, "crusader/metfire.wav"); + self.attack_finished=time + 1.5; + self.effects(+)EF_MUZZLEFLASH; + makevectors(self.v_angle); + meteor.speed=1600; + meteor.o_angle=normalize(v_forward); + meteor.velocity=meteor.o_angle*meteor.speed; + meteor.lifetime=time + 5; + meteor.th_die=MegaMeteorIgnite; + meteor.nextthink = time + 0.1; + meteor.dmg=60; + meteor.movetype=MOVETYPE_FLYMISSILE; + meteor.health = 6; + + setsize(meteor,'0 0 0', '0 0 0'); + meteor.movedir = normalize(meteor.velocity); +// meteor.effects(+)EF_BRIGHTLIGHT|EF_TORNADO_EFFECT; + meteor.effects(+)EF_NODRAW; + meteor.drawflags(+)MLS_FIREFLICKER|DRF_TRANSLUCENT;//|MLS_ABSLIGHT; + + meteor.owner=self; + //meteor.solid=SOLID_PHASE; + meteor.solid=SOLID_BBOX; + meteor.touch=MegaMeteorTouch; + + org=self.origin+self.proj_ofs+v_forward*12; + setorigin(meteor,org); + + + entity oldself; + oldself = self; + self = meteor; + + meteor.think = MegaMeteorThink; + meteor.think(); + + self = oldself; +} + +void()meteor_ready_loop; +void() Cru_Met_Attack; + +void meteor_power_fire (void) +{ + self.wfs = advanceweaponframe($fire1,$fire9); + self.th_weapon=meteor_power_fire; + if(self.weaponframe==$fire2 && self.attack_finished<=time) + { + FireMeteorTornado(); + } + + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.last_attack=time; + meteor_ready_loop(); + } +} + +void meteor_fire (void) +{ + self.wfs = advanceweaponframe($fire1,$fire9); + self.th_weapon=meteor_fire; + + if((!self.button0||self.attack_finished>time)&&self.wfs==WF_CYCLE_WRAPPED) + { + self.last_attack=time; + meteor_ready_loop(); + } + else if(self.weaponframe==$fire1 &&self.attack_finished<=time) + FireMeteor("meteor"); +} + +void() Cru_Met_Attack = +{ + if(self.artifact_active&ART_TOMEOFPOWER) + self.th_weapon=meteor_power_fire; + else + self.th_weapon=meteor_fire; + thinktime self : 0; +}; + +void meteor_ready_loop (void) +{ + self.weaponframe = $idle; + self.th_weapon=meteor_ready_loop; +} + +void meteor_select (void) +{ +//go to ready loop, not relaxed? + self.wfs = advanceweaponframe($Select1,$Select16); + self.weaponmodel = "models/meteor.mdl"; + self.th_weapon=meteor_select; + self.last_attack=time; + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + meteor_ready_loop(); + } +} + +void meteor_deselect (void) +{ + self.wfs = advanceweaponframe($Select16,$Select1); + self.th_weapon=meteor_deselect; + + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + diff --git a/mezzoman.hc b/mezzoman.hc new file mode 100644 index 0000000..a5d860d --- /dev/null +++ b/mezzoman.hc @@ -0,0 +1,1623 @@ +/* + * $Header: /HexenWorld/Siege/mezzoman.hc 8 6/01/98 2:49a Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\mezzoman\FINAL\mezzoman.hc +MG!!! +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\mezzoman\FINAL +$origin 0 0 -2 +$base BASE skin1 +$skin skin1 +$skin Skin2 +$flags 16384 + +// +$frame block1 block2 block3 block4 block5 +$frame block6 + +// +$frame charge1 charge2 charge3 charge4 charge5 +$frame charge6 charge7 charge8 charge9 charge10 +$frame charge11 charge12 charge13 charge14 charge15 +$frame charge16 charge17 charge18 charge19 charge20 +$frame charge21 charge22 charge23 charge24 charge25 + +// +$frame clober1 clober2 clober3 clober4 clober5 +$frame clober6 clober7 clober8 clober9 clober10 +$frame clober11 clober12 clober13 clober14 clober15 +$frame clober16 + +// +$frame death1 death2 death3 death4 death5 +$frame death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 +$frame death16 + +// +$frame dive1 dive2 dive3 dive4 dive5 +$frame dive6 dive7 dive8 dive9 dive10 +$frame dive11 dive12 dive13 dive14 dive15 +$frame dive16 dive17 dive18 + +// +$frame jump1 jump2 jump3 jump4 jump5 +$frame jump6 jump7 jump8 jump9 jump10 +$frame jump11 jump12 jump13 jump14 jump15 +$frame jump16 jump17 jump18 jump19 jump20 +$frame jump21 jump22 + +// +$frame pain1 pain2 pain3 pain4 pain5 +$frame pain6 pain7 + +// +$frame roar1 roar2 roar3 roar4 roar5 +$frame roar6 roar7 roar8 roar9 roar10 +$frame roar11 roar12 roar13 roar14 roar15 +$frame roar16 roar17 roar18 roar19 roar20 +$frame roar21 roar22 roar23 roar24 roar25 +$frame roar26 roar27 roar28 roar29 roar30 + +// +$frame Roll1 Roll2 Roll3 Roll4 Roll5 +$frame Roll6 Roll7 Roll8 Roll9 Roll10 +$frame Roll11 Roll12 Roll13 Roll14 Roll15 +$frame Roll16 Roll17 Roll18 + +// +$frame run1 run2 run3 run4 run5 +$frame run6 run7 run8 run9 run10 +$frame run11 run12 run13 run14 run15 +$frame run16 run17 run18 run19 run20 +$frame run21 run22 + +// +$frame stand1 stand2 stand3 stand4 stand5 +$frame stand6 stand7 stand8 stand9 stand10 + +// +$frame sword1 sword2 sword3 sword4 sword5 +$frame sword6 sword7 sword8 sword9 sword10 +$frame sword11 sword12 sword13 + +// +$frame twirl1 twirl2 twirl3 twirl4 twirl5 +$frame twirl6 twirl7 twirl8 twirl9 twirl10 + +// +$frame walk1 walk2 walk3 walk4 walk5 +$frame walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 walk13 walk14 walk15 +$frame walk16 walk17 walk18 walk19 walk20 +$frame walk21 walk22 walk23 walk24 walk25 +$frame walk26 walk27 walk28 walk29 walk30 + + +void() mezzo_skid; +void() mezzo_block; +void() mezzo_block_wait; +void() mezzo_jump; +void() mezzo_roar; +void() mezzo_in_air; +void() mezzo_run_loop; +void()mezzo_charge; + +void mezzo_idle_sound () +{ +string soundstr; + if(random()<0.5) + soundstr="mezzo/snort.wav"; + else + soundstr="mezzo/growl.wav"; + sound(self,CHAN_VOICE,soundstr,1,ATTN_NORM); +} + +/* +void mezzo_possum_up (void)// [-- $death14..$death1] +{ + if (cycle_wrapped) + self.think=self.th_run; +} + +void mezzo_playdead (void) +{ +// self.frame=$death14; + self.think=mezzo_playdead; + thinktime self : 0.1; + ai_stand(); +} +*/ + +void mezzo_roll_right () [-- $Roll18 .. $Roll1] +{ +// if(self.shield.velocity!='0 0 0'&&self.shield.model!="models/null.spr") +// dprint("what the?\n"); +//SOUND? +vector rollangle; + makevectors(self.angles); + rollangle=vectoangles(v_right); +// if(!walkmove(rollangle_y,7,FALSE)&&self.frame>$Roll5 &&self.flags&FL_ONGROUND) +// self.frame=$Roll5; + walkmove(rollangle_y,7,FALSE); + if(cycle_wrapped) + { + thinktime self : 0; + if(!self.flags&FL_ONGROUND) + self.think=mezzo_in_air; + else + self.think=self.th_run; + } +} + +void mezzo_roll_left () [++ $Roll1 .. $Roll18] +{ +// if(self.shield.velocity!='0 0 0'&&self.shield.model!="models/null.spr") +// dprint("what the?\n"); +//SOUND? +vector rollangle; + makevectors(self.angles); + rollangle=vectoangles(v_right); +// if(!walkmove(rollangle_y,-7,FALSE)&&self.frame<$Roll14 &&self.flags&FL_ONGROUND) +// self.frame=$Roll14; + walkmove(rollangle_y,-7,FALSE); + if(cycle_wrapped) + { + thinktime self : 0; + if(!self.flags&FL_ONGROUND) + self.think=mezzo_in_air; + else + self.think=self.th_run; + } +} + +void mezzo_roll_forward () [++ $dive1 .. $dive18] +{ +//SOUND? +//vector rollangle; +// if(!walkmove(self.angles_y,7,FALSE)&&self.frame<$dive12 &&self.flags&FL_ONGROUND) +// self.frame=$dive12; + if(!self.flags&FL_ONGROUND) + { + if(!infront(self.enemy))//stay facing enemy so if land behind him, will be facing him + ai_face(); + } + else + { + if(self.dflags) + { + sound(self,CHAN_BODY,"player/land.wav",1,ATTN_NORM); + self.dflags=FALSE; + } + walkmove(self.angles_y,7,FALSE); + } + + if(cycle_wrapped) + { + thinktime self : 0; + if(!self.flags&FL_ONGROUND) + self.think=mezzo_in_air; + else + self.think=self.th_run; + } +} + +void mezzo_duck () [++ $jump13 .. $jump22] +{ +//FIXME: Have him keep checking for befense when staying down for .5 sec +vector newmaxs; + if(self.frame==$jump14) + { + newmaxs=self.maxs; + newmaxs_z=self.maxs_z*0.5; + setsize(self,self.mins,newmaxs); + } + else if(self.frame==$jump18) + { + newmaxs=self.maxs; + newmaxs_z=self.maxs_z*2; + setsize(self,self.mins,newmaxs); + } + else if(self.frame==$jump16) + thinktime self : 0.5; + else if(cycle_wrapped) + { + thinktime self : 0; + self.think=self.th_run; + } +} + +float mezzo_check_duck (entity proj) +{ +entity proj_owner; +vector proj_mins,duck_hite,proj_dir; +vector temp_f,temp_r,temp_u; + + duck_hite=self.origin; + duck_hite_z=self.origin_z + self.maxs_z/2; + if(proj==self.enemy) + { + proj_owner=proj; + proj_mins=self.enemy.origin+self.enemy.proj_ofs; + temp_f=v_forward; + temp_r=v_right; + temp_u=v_up; + if(self.enemy.classname=="player") + makevectors(self.enemy.v_angle); + else + makevectors(self.enemy.angles); + proj_dir=v_forward; + v_forward=temp_f; + v_right=temp_r; + v_up=temp_u; + } + else + { + proj_owner=proj.owner; + proj_mins=proj.origin; + proj_mins_z=proj.origin_z - proj.mins_z; + proj_dir=normalize(duck_hite-proj_mins); + } + if(!proj_owner) + proj_owner=proj; + + traceline(proj_mins,duck_hite+proj_dir*8,FALSE,proj_owner); + + if(trace_ent!=self)//||trace_endpos_z>duck_hite_z) + { + dprint(trace_ent.classname); + dprint(" at end of trace- ok to duck!\n"); + return TRUE; + } + else + return FALSE; +} + +float mezzo_check_jump (entity proj) +{ +float impact_hite, jump_hite; +vector proj_dir, proj_top; + + if(!self.flags&FL_ONGROUND) + return FALSE; + + proj_dir=normalize(proj.velocity); + proj_top=proj.origin; + proj_top_z=proj.absmax_z; + traceline(proj_top,proj_top+proj_dir*1000,FALSE,proj); + if(trace_ent!=self) + return FALSE; + + impact_hite=trace_endpos_z; + tracearea(self.origin,self.origin+'0 0 256',self.mins,self.maxs,FALSE,self); + jump_hite=trace_fraction*256; + if(jump_hite<24) + return FALSE; + else if(jump_hite>133) + jump_hite=133; + else if(jump_hite<77) + jump_hite=77; + + if(self.origin_z+jump_hite/2>impact_hite+proj.maxs_z&&random()<0.7) + { + self.velocity_z=jump_hite*3; + self.flags(-)FL_ONGROUND; + return TRUE; + } + + return FALSE; +} + +void mezzo_choose_roll (entity proj) +{ +float proj_dir; + proj_dir=check_heading_left_or_right(proj); + if(proj_dir==0) + { + if(mezzo_check_duck(proj)) + { + thinktime self : 0; + self.think=mezzo_duck; + } + else + { + thinktime self : 0; + self.think=mezzo_block; + } + return; + } + else + { +//FIXME: Probably shouldn't try to roll in the other direction + makevectors(self.angles); + if(solid_under(self.origin, self.origin+v_right*105*proj_dir)) + tracearea(self.origin, self.origin+v_right*105*proj_dir,self.mins,self.maxs,FALSE,self); + else + trace_fraction=FALSE; + if(trace_fraction==1) + { + traceline(trace_endpos, trace_endpos-'0 0 300',TRUE,self); + if(pointcontents(trace_endpos)!=CONTENT_EMPTY) + trace_fraction=FALSE; + else + trace_fraction=TRUE; + } + if(trace_fraction==1) + { + if(proj_dir>0) + { + thinktime self : 0; + self.think=mezzo_roll_right; + } + else + { + thinktime self : 0; + self.think=mezzo_roll_left; + } + return; + } + else if(mezzo_check_duck(proj)) + { + thinktime self : 0; + self.think=mezzo_duck; + } + else + { + thinktime self : 0; + self.think=mezzo_block; + } +/* { + tracearea(self.origin, self.origin+v_right*36*proj_dir*-1,self.mins,self.maxs,FALSE,self); + if(trace_fraction==1) + { + if(proj_dir*-1>0) + { + thinktime self : 0; + self.think=mezzo_roll_right; + } + else + { + thinktime self : 0; + self.think=mezzo_roll_left; + } + return; + } + } +*/ + } +} + +void mezzo_check_defense () +{ +// if(self.shield.velocity!='0 0 0'&&self.shield.model!="models/null.spr") +// dprint("what the?\n"); +//NOTE: Add random chance of failure based on difficulty level - highest diff means no chance of failure here + if(skill+self.strength/5=0) + self.think=mezzo_duck; + else if(self.think==mezzo_block_wait) + { + self.t_width=time+1; + return; + } + else if(self.think==mezzo_run_loop||random()<0.3) + self.think=mezzo_charge; + else + self.think=mezzo_block; + return; + } + else if(random()<0.5) + mezzo_choose_roll(enemy_proj); + else if(random()<0.7||self.enemy.v_angle_x>=0) + self.think=mezzo_duck; + else if(self.think==mezzo_block_wait) + { + self.t_width=time+1; + return; + } + else if(self.think==mezzo_block_wait) + { + self.t_width=time+1; + return; + } + else if(self.think==mezzo_run_loop||random()<0.3) + self.think=mezzo_charge; + else + self.think=mezzo_block; + return; + } + + if(self.level>0.3)//I've got 0.3 seconds before impact + { + mezzo_choose_roll(enemy_proj); + return; + } + else if(mezzo_check_duck(enemy_proj)) + { + thinktime self : 0; + tracearea(self.origin,self.origin+v_forward*64,self.mins,'16 16 20',FALSE,self); + if(trace_fraction<1||random()<0.2||!infront(enemy_proj)) + self.think=mezzo_duck; + else + self.think=mezzo_roll_forward; + return; + } + else if(mezzo_check_jump(enemy_proj)) + { + self.think=mezzo_jump; + enemy_infront=infront(self.enemy); + enemy_vis=visible(self.enemy); + trace_fraction=0; + if((random()<0.3||self.think==mezzo_run_loop)&&enemy_infront&&enemy_vis&&self.enemy!=world)//Jump towards enemy + { + vector enemy_dir; + enemy_dir=normalize(self.enemy.origin-self.origin); + traceline(self.origin,self.origin+enemy_dir*64+'0 0 56',FALSE,self); + if(trace_fraction==1) + { + traceline(trace_endpos,trace_endpos-'0 0 300',TRUE,self); + if(pointcontents(trace_endpos)==CONTENT_EMPTY) + { + self.velocity_x=self.velocity_y=0; + self.velocity+=enemy_dir*vlen(self.enemy.origin-self.origin); + trace_fraction=1; + if(random()<0.7) + self.think=mezzo_roll_forward; + else + self.think=self.th_jump; + } + else + { +// dprint("might land in water or lava\n"); + trace_fraction=0; + } + } + else + { +// dprint("not enough room in front \n"); + trace_fraction=0; + } + } +// dprint(ftos(trace_fraction)); +// dprint(" is the trace_fraction\n"); + if(random()<0.5&&trace_fraction<1)//Jump to side + { +// dprint("checking to sides\n"); + if(random()<0.5) + r=1; + else + r=-1; + makevectors(self.angles); + traceline(self.origin,self.origin+v_right*36*r+'0 0 56',FALSE,self); + if(trace_fraction<1) + { + traceline(self.origin,self.origin-v_right*36*r+'0 0 56',FALSE,self); + if(trace_fraction<1) + { +// dprint("not enough room to jump on that side\n"); + self.think=mezzo_jump; + } + else + { + traceline(trace_endpos,trace_endpos-'0 0 300',TRUE,self); + if(pointcontents(trace_endpos)!=CONTENT_EMPTY) + { +// dprint("might jump into water or lava\n"); + self.think=mezzo_jump; + } + else + { + self.velocity-=v_right*r*200; + if(r*-1>0) + self.think=mezzo_roll_right; + else + self.think=mezzo_roll_left; + } + } + } + else + { + traceline(trace_endpos,trace_endpos-'0 0 300',TRUE,self); + if(pointcontents(trace_endpos)!=CONTENT_EMPTY) + { +// dprint("might jump into water or lava\n"); + self.think=mezzo_jump; + } + else + { + self.velocity+=v_right*r*200; + if(r>0) + self.think=mezzo_roll_right; + else + self.think=mezzo_roll_left; + } + } + } + thinktime self : 0; + if(self.think!=mezzo_jump&&self.think!=mezzo_roll_right&&self.think!=mezzo_roll_left&&self.think!=mezzo_roll_forward) + { +// dprint("What the FUCK!!!\n"); + self.think=mezzo_jump; + } +// return; + } + else if(infront(enemy_proj)&&random()<0.5) + { + thinktime self : 0; + if(self.think==mezzo_block_wait) + { + self.t_width=time+1; + return; + } + else if(self.think==mezzo_run_loop||random()<0.3) + self.think=mezzo_charge; + else + self.think=mezzo_block; + return; + } +} + +void() mezzo_charge_stop; +void mezzo_slam () +{ + if(!other.movetype||other.mass>100||other.solid==SOLID_BSP) + return; + + if(!infront(other)||other.safe_time>time) + return; + + if(other.origin_z>self.absmax_z - 6||other.absmax_ztime) return; + + if(!self.owner.flags2&FL_ALIVE||self.owner.frozen>0) + { + if(self.owner.movechain==self) + self.owner.movechain=world; + remove(self); + } + + if(other.classname=="funnal"||other.classname=="tornato") + return; + + dir = normalize(other.velocity); + magnitude=vlen(other.velocity); + org = other.origin; + vec = org + dir*100; + traceline (org, vec, FALSE, other); + + if(trace_ent!=self.owner) + return; + + if(self.owner.classname=="monster_mezzoman") + sound(self,CHAN_AUTO,"mezzo/slam.wav",1,ATTN_NORM); + + if(!self.owner.strength&&self.owner.classname=="monster_mezzoman") + {//Just block it + if(!other.flags2&FL_ALIVE) + other.flags2(+)FL_NODAMAGE; + } + else + {//reflect! + if(self.owner.classname!="monster_mezzoman") + { + sound (self, CHAN_WEAPON, "fangel/deflect.wav", 1, ATTN_NORM); + CreateWhiteFlash(trace_endpos); + if(self.owner.classname=="monster_fallen_angel") + { + dir=dir*-1; + makevectors(dir); + dir=v_forward + v_up*random(-0.75,.75) + v_right*random(-0.75,.75); + dir=normalize(dir); + } + else// if(visible(other.owner)) + { + v_forward=normalize(other.owner.origin+other.owner.view_ofs-other.origin); + dir+= 2*v_forward; + dir=normalize(dir); + } +// else +// dir=dir*-1; + } + else + { + sound(self,CHAN_AUTO,"mezzo/reflect.wav",1,ATTN_NORM); + starteffect(CE_MEZZO_REFLECT,self.origin); + makevectors(trace_ent.angles); + dir+= 2*v_forward; + dir=normalize(dir); + } + + if(other.movedir) + other.movedir=dir; + if(other.o_angle) + other.o_angle=dir; + + if(magnitude20) + zofs=20; + else if(zofs<-20) + zofs=-20; + + traceline(self.origin+'0 0 30',self.origin+'0 0 30'+v_forward*36+v_up*zofs,FALSE,self); + if(trace_fraction==1) + return; + + sound(self,CHAN_VOICE,"mezzo/slam.wav",1,ATTN_NORM); + + if(trace_ent.movetype&&trace_ent.movetype!=MOVETYPE_PUSH) + trace_ent.velocity+=v_forward*200-v_right*100+'0 0 100'; + if(trace_ent.takedamage) + T_Damage(trace_ent,self,self,5*(self.strength+1)*(self.aflag+1)*2);//(coop + 1)); + if(trace_ent.classname=="player") + if(infront_of_ent(self,trace_ent)) + trace_ent.punchangle_y=4; + } + else if(cycle_wrapped) + { + self.attack_finished=time+0.5; + thinktime self : 0; + self.think=self.th_run; + } + else if(self.frame==$clober1) + { + self.last_attack=time; + if(random()<0.5) + sound(self,CHAN_VOICE,"mezzo/attack.wav",1,ATTN_NORM); + } +} + +/* +void mezzo_sword() [++ $sword1 .. $sword13] +{ + ai_face(); + ai_charge(3); + if(cycle_wrapped) + { + self.attack_finished=time+0.3; + thinktime self : 0; + self.think=self.th_run; + } + else if(self.frame==$sword1) + { + self.last_attack=time; + sound(self,CHAN_WEAPON,"weapons/vorpswng.wav",1,ATTN_NORM); + if(random()<0.5) + sound(self,CHAN_VOICE,"mezzo/attack.wav",1,ATTN_NORM); + } + else if(self.frame>=$sword6 && self.frame<=$sword10) + { + float ofs,zofs; + vector dir; + makevectors(self.angles); + ofs=($sword10 - self.frame)*4; + dir_z=ofs - 8; + dir+=v_right*(ofs - 8)+v_forward*(48 - fabs(16 - ofs)); + dir=normalize(dir); + + zofs = self.enemy.origin_z - self.origin_z; + if(zofs>20) + zofs=20; + else if(zofs<-20) + zofs=-20; + + traceline(self.origin+'0 0 37',self.origin+'0 0 37'+dir*48+v_up*zofs,FALSE,self); + if(trace_fraction==1) + return; + + if(self.t_width=4) + self.attack_finished=0; + else + self.attack_finished=time+0.3; + thinktime self : 0; + self.think=self.th_run; + } + else if(self.frame==$sword1) + { + self.last_attack=time; + sound(self,CHAN_WEAPON,"weapons/vorpswng.wav",1,ATTN_NORM); + if(random()<0.5) + sound(self,CHAN_VOICE,"mezzo/attack.wav",1,ATTN_NORM); + } + else if(self.frame>=$sword6 && self.frame<=$sword10) + { + float ofs,zofs; + vector dir; + makevectors(self.angles); + ofs=($sword10 - self.frame)*4; + dir=v_right*(ofs - 8)+v_forward*(48 - fabs(16 - ofs))+'0 0 1'*(ofs - 8); + dir=normalize(dir); + + zofs = (self.enemy.origin_z+self.enemy.view_ofs_z) - (self.origin_z+37); + if(zofs>36) + zofs=36; + else if(zofs<-36) + zofs=-36; + + traceline(self.origin+'0 0 37'+'0 0 1'*zofs,self.origin+'0 0 37'+dir*48+'0 0 1'*zofs,FALSE,self); + if(trace_fraction==1) + return; + + if(self.t_widthdamage*3||self.pain_finished>time)//only react to 33 percent of current health damage + return; + + self.monster_awake=TRUE; + + if(self.shield) + remove(self.shield); + + if(self.health<=100) + { + self.th_pain=SUB_Null; + if(self.health<=100) + { + if(random()<0.5) + { + self.oldthink=self.th_run; + self.think=mezzo_roar; + self.speed=15; + self.yaw_speed=20; + self.aflag=TRUE;//Berzerk! + } + else if(!self.flags&FL_ONGROUND) + self.think=mezzo_in_air; + else + self.think=self.th_run; + } + } + else + { + sound(self,CHAN_VOICE,"mezzo/pain.wav",1,ATTN_NORM); + if((!self.enemy||!visible(self.enemy))&&attacker.siege_team!=self.siege_team) + { + if(self.enemy!=world&&self.enemy!=attacker) + self.oldenemy=self.enemy; + self.enemy=attacker; + } + self.pain_finished=time+1+self.strength; + self.think=mezzo_pain_seq; + } + thinktime self : 0; +} + +void mezzo_land () [++ $jump13 .. $jump22] +{ +//SOUND? +// dprint("landing\n"); + if(cycle_wrapped) + { + thinktime self : 0; + self.think=self.th_run; + } + else if(self.frame==$jump13) + sound(self,CHAN_BODY,"player/land.wav",1,ATTN_NORM); +} + +void mezzo_in_air () +{ +// dprint("in air\n"); + self.frame=$jump12; + if(self.flags&FL_ONGROUND) + { + thinktime self : 0; + self.think=mezzo_land; + } + else + { + if(self.velocity=='0 0 0') + self.velocity='0 0 -60'; + self.think=mezzo_in_air; + if(vlen(self.velocity)>300) + { + if(random()<0.5) + { + self.dflags=TRUE;//in air + self.think=mezzo_roll_forward; + } + } + thinktime self : 0.05; + } +} + +void mezzo_jump () [++ $jump1 .. $jump11] +{ +//SOUND? +// dprint("jumping\n"); + ai_face(); + if(self.flags&FL_ONGROUND) + { + thinktime self : 0; + self.think=mezzo_land; + } + else if(self.frame==$jump11) + { + thinktime self : 0.05; + self.think=mezzo_in_air; + } +} + +void mezzo_charge_stop () [++ $charge15 .. $charge25] +{ + if(cycle_wrapped) + { + self.touch=obj_push; + thinktime self : 0; + self.think=self.th_run; + } + if(!walkmove(self.angles_y,$charge25 - self.frame,FALSE)) + { + if(!self.ltime) + self.think=mezzo_pain_seq; + else + self.think=self.th_run; + thinktime self : 0; + } +} + +void mezzo_charge_leap () [++ $charge9 .. $charge14] +{ +//SOUND? + if(cycle_wrapped) + { + thinktime self : 0; + self.think=mezzo_charge_stop; + } + else if(self.frame==$charge9) + { + makevectors(self.angles); + traceline(self.origin+'0 0 25',self.origin+'0 0 25'+v_forward*256,FALSE,self); +//Used to make him not charge if you stepped aside, now +//only checks if will fall + if(!trace_ent.takedamage) + { + self.think=mezzo_skid; + thinktime self : 0; + } + else + { + traceline(trace_endpos,trace_endpos-'0 0 300',TRUE,self); + if(pointcontents(trace_endpos)!=CONTENT_EMPTY||trace_fraction==1) + { + self.think=mezzo_skid; + thinktime self : 0; + } + else if(self.flags&FL_ONGROUND) + { + if(random()<0.5) + sound(self,CHAN_VOICE,"mezzo/attack.wav",1,ATTN_NORM); + self.velocity=v_forward*700+'0 0 133'; + self.flags(-)FL_ONGROUND; + } + else + { + self.think=mezzo_in_air; + thinktime self : 0; + } + } + } +} + +void mezzo_charge () [++ $charge1 .. $charge8] +{ + if(cycle_wrapped) + { + thinktime self : 0; + self.think=mezzo_charge_leap; + } + else if(self.frame==$charge1) + { + self.last_attack=time; + self.ltime=0; + self.touch=mezzo_slam; + self.attack_finished=time+1.25; + } + walkmove(self.angles_y,15,FALSE); +} + +void mezzo_block_return () [-- $block6 .. $block1] +{ +// if(self.shield.velocity!='0 0 0'&&self.shield.model!="models/null.spr") +// dprint("what the?\n"); + if(cycle_wrapped) + { + float r; + if(self.shield) + remove(self.shield); + r=vlen(self.enemy.origin-self.origin); + if(infront(self.enemy)&&r<100) + { + thinktime self : 0; + self.think=self.th_melee; + } +// else if(random()<0.2&&r<177) +// { +// thinktime self : 0; +// self.think=self.th_stand; +// } + else + { + thinktime self : 0; + self.think=self.th_run; + } + } +} + +void mezzo_block_wait () +{ +// if(self.shield.velocity!='0 0 0'&&self.shield.model!="models/null.spr") +// dprint("what the?\n"); + self.think=mezzo_block_wait; + if(self.t_width77) + self.th_pain=mezzo_pain; + self.t_width=time+1; + thinktime self : 0; + self.think=mezzo_block_wait; + } + else if(self.frame==$block1) + spawn_reflect(); +} + +void mezzo_skid () [++ $block1 .. $block6] +{ +float skidspeed, anim_stretch; + anim_stretch = 3; + + skidspeed=$block6 - self.frame + anim_stretch - self.level; + if(walkmove(self.angles_y,skidspeed*2,FALSE)) + { + particle(self.origin, '0 0 20'*skidspeed, 344, skidspeed); + if(random()<0.2) + CreateWhiteSmoke(self.origin,'0 0 8',HX_FRAME_TIME * 2); + } + else + { + thinktime self : 0; + self.think=mezzo_block_return; + return; + } + + if(cycle_wrapped) + { + self.attack_finished=time+3; + thinktime self : 0; + self.think=mezzo_block_return; + } + else if(self.frame==$block1) + { + spawn_reflect(); + sound(self,CHAN_AUTO,"mezzo/skid.wav",1,ATTN_NORM); + } + else if(self.level33) + { + if(random()<0.5&&lineofsight(self.enemy,self)) + { + thinktime self : 0; + self.think=mezzo_charge; + } + else if(dist>84&&self.last_attacktime) + dropStep(); + else + self.effects(-)EF_NODRAW; +} + +void mezzo_run_loop () [++ $run1 .. $run22] +{ + mezzo_run_think(); +} + +void mezzo_run () [++ $run6 .. $run22] +{ + mezzo_check_defense(); + self.last_attack=time+0.1;//So won't start running then skid suddenly + if(!self.monster_awake) + if(range(self.enemy)>RANGE_NEAR&&random()>0.3) + { + self.oldthink=self.th_run; + self.think=mezzo_roar; + thinktime self : 0; + return; + } + else + { + sound(self,CHAN_VOICE,"mezzo/attack.wav",1,ATTN_NORM); + self.monster_awake=TRUE; + } + + if(cycle_wrapped) + { + self.think=mezzo_run_loop; + thinktime self : 0; + } + else + mezzo_run_think(); +} + +void mezzo_walk () [++ $walk1 .. $walk30] +{ + if(self.frame==$stand3 &&random()<0.1) + mezzo_idle_sound(); + mezzo_check_defense(); + ai_walk(3); + if(self.enemy) + if(CheckAnyAttack()) + return; +} + +void()mezzo_stand; +void mezzo_twirl() [++ $twirl1 .. $twirl10] +{ + mezzo_check_defense(); + if(cycle_wrapped) + { + self.think=mezzo_stand; + thinktime self : 0; + } + else if(self.frame==$twirl1) + { + sound(self,CHAN_WEAPON,"weapons/vorpswng.wav",0.7,ATTN_NORM); + if(random()<0.5) + mezzo_idle_sound(); + } + ai_stand(); +} + +void mezzo_stand2 () [-- $stand10 .. $stand1] +{ + mezzo_check_defense(); + + if(self.level<3&&self.frame<$stand10) + { + self.level+=1; + self.frame+=1; + } + else + self.level=0; + + if(self.frame==$stand1) + { + if(random()<0.1||(self.monster_awake&&random()<0.5)) + self.think=mezzo_twirl; + else + self.think=mezzo_stand; + thinktime self : 0; + return; + } + else if(self.frame==$stand10 &&random()<0.1) + mezzo_idle_sound(); + +/* if(self.monster_awake) + { + float r; + r=vlen(self.enemy.origin-self.origin); + if(random()<0.1||r>177) + { + if(r>177) + self.think=self.th_run; + else if(enemy_infront&&enemy_vis&&r<133) + self.think=mezzo_charge; + else if(random()<0.5) + self.think=self.th_run; + else + self.think=self.th_walk; + thinktime self : 0; + } + else + { + if(random()<0.8&&r>100) + self.attack_finished=time+0.1; + ai_run(0); + } + } + else +*/ ai_stand(); +} + +void mezzo_stand () [++ $stand1 .. $stand10] +{ + if(random()<0.5) + { + mezzo_check_defense(); + + if((!self.enemy.flags2&FL_ALIVE&&self.enemy!=world)||self.enemy==world) + { + self.monster_awake=FALSE; + if(self.oldenemy.flags2&FL_ALIVE) + { + self.enemy=self.oldenemy; + self.oldenemy=world; + } + else + self.enemy=world; + } + } + + if(self.level<3&&self.frame>$stand1) + { + self.level+=1; + self.frame-=1; + } + else + self.level=0; + + if(self.frame==$stand10) + { + self.think=mezzo_stand2; + thinktime self : 0; + return; + } + else if(self.frame==$stand1 &&random()<0.1) + mezzo_idle_sound(); + + if(random()<0.5) + ai_stand(); +} + + +/*QUAKED monster_werejaguar (1 0.3 0) (-16 -16 0) (16 16 56) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +WereCat with jaguar skin +If they're targetted by a trigger and used, they'll atack the activator of the target +If they can't see the activator, they'll roll left or right (in the direction of the activator) +Their roll is 128 units long, so place the mezzoman 128 units away from where you want the roll to stop + +My babies!!! - MG +*/ +//IDEA: Have mezzoman do ai_face while in air or rolling so always faces you when lands/gets up? +void() monster_werejaguar = +{ +// if (deathmatch) +// { +// remove(self); +// return; +// } + + if (!self.flags2&FL_SUMMONED) + { + precache_model2 ("models/mezzoman.mdl"); + precache_model2 ("models/mezzoref.spr"); + precache_model2 ("models/h_mez.mdl"); + precache_sound2 ("mezzo/skid.wav"); + precache_sound2 ("mezzo/roar.wav"); + precache_sound2 ("mezzo/reflect.wav"); + precache_sound2 ("mezzo/slam.wav"); + precache_sound2 ("mezzo/pain.wav"); + precache_sound2 ("mezzo/die.wav"); + precache_sound2 ("mezzo/growl.wav"); + precache_sound2 ("mezzo/snort.wav"); + precache_sound2 ("mezzo/attack.wav"); + } + self.solid = SOLID_SLIDEBOX; + self.takedamage=DAMAGE_YES; + self.thingtype=THINGTYPE_FLESH; + self.movetype = MOVETYPE_STEP; + self.view_ofs = '0 0 53'; + self.speed=10; + self.yaw_speed = 10; + self.experience_value = 150; + self.monsterclass = CLASS_HENCHMAN; + self.mass = 10; + self.mintel = 15;//Animal sense of smell makes him a good tracker + if(self.classname=="monster_werepanther") + { + self.monsterclass = CLASS_LEADER; + self.experience_value = 300; + if(!self.health) + self.health=400; + } + else if(!self.health) + self.health = 250; + + self.strength = 1; + self.classname="monster_mezzoman"; + + self.th_stand=mezzo_stand; + self.th_walk=mezzo_walk; + self.th_run=mezzo_run; + self.th_pain=mezzo_pain; + self.th_melee=mezzo_melee; + self.th_missile=mezzo_missile; + self.th_jump=mezzo_jump; + self.th_die=mezzo_die; + self.spawnflags (+) JUMP; + + setmodel (self, "models/mezzoman.mdl"); + self.headmodel="models/h_mez.mdl"; + + setsize (self, '-16 -16 0', '16 16 56'); + + self.frame=$stand1; + + walkmonster_start(); +}; + +void monster_mezzoman (void) +{ + monster_werejaguar(); +} + +/*QUAKED monster_werepanther (1 0.3 0) (-16 -16 0) (16 16 56) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +TIGER Skins for siege +*/ +void monster_werepanther (void) +{ + monster_werejaguar(); +} + diff --git a/mirage.hc b/mirage.hc new file mode 100644 index 0000000..c04a7a5 --- /dev/null +++ b/mirage.hc @@ -0,0 +1,253 @@ +/* + * $Header: /HexenWorld/Siege/Mirage.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +MIRAGE + +============================================================================== +*/ +$cd id1/models/player_4 +$origin 0 -6 24 +$base base +$skin skin + +$frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6 + + + + + + +/* +============================================================================== +MIRAGE FRAMES +============================================================================== +*/ + +void ai_mirage(float dist); + +void() mirage_run1 =[ $axrun1, mirage_run2 ] +{ + if(time > self.ltime) + { + self.owner.holo_engaged = 0; + remove(self); + return; + } + if(time + 3 > self.ltime) + self.model = string_null; + ai_mirage(11); +}; +void() mirage_run2 =[ $axrun2, mirage_run3 ] {ai_mirage(8);}; +void() mirage_run3 =[ $axrun3, mirage_run4 ] +{ + if(time + 3 > self.ltime) + self.model = "models/player.mdl"; + ai_mirage(10); +}; +void() mirage_run4 =[ $axrun4, mirage_run5 ] {ai_mirage(10);}; +void() mirage_run5 =[ $axrun5, mirage_run6 ] {ai_mirage(8);}; +void() mirage_run6 =[ $axrun6, mirage_run1 ] {ai_mirage(15);}; + + + + + +/* + * ai_mirage() -- The so-called "intelligence" of the Mirage. + */ + +void ai_mirage(float dist) +{ + local vector delta; + local float axis; + local float direct, ang_rint, ang_floor, ang_ceil; + + movedist = dist; + + if(self.enemy.health <= 0) + { + self.enemy = world; + if(self.oldenemy.health > 0) + { + self.enemy = self.oldenemy; + HuntTarget(); + } + else { + self.th_run(); + return; + } + } + + self.show_hostile = time + 1; // wake up monsters + + enemy_vis = visible(self.enemy); + if(enemy_vis) + self.search_time = time + 5; + + if(coop && self.search_time < time) + if(FindTarget()) + return; + + enemy_infront = infront(self.enemy); + enemy_range = range(self.enemy); + enemy_yaw = vectoyaw(self.enemy.origin - self.origin); + +// if(CheckAnyAttack()) +// return; // beginning a fake attack + + if(self.attack_state == AS_SLIDING) + { + ai_run_slide(); + return; + } + + movetogoal(dist); +} + + + + +/* + * remove_mirage() -- Removes the Mirage belonging to self from the world. + */ + +void remove_mirage() +{ + local entity mirage; + mirage = world; + + while(mirage.owner != self) + { + mirage = find(mirage, classname, "mirage"); + if(mirage == world) + { + bprint("Error: Mirage not found\n"); + return; + } + } + remove(mirage); + bprint("Mirage disengaged\n"); + if(time + 0.5 > mirage.ltime) + self.holo_engaged = 0; + else + self.holo_engaged = mirage.ltime - time; +} + + + + +/* + * init_mirage() -- Sets the Mirage entity fields after spawning. + */ + +void init_mirage() +{ + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_STEP; + + setmodel(self, self.owner.model); + setsize(self, '-16 -16 -24', '16 16 40'); + self.health = 666; + self.weapon = IT_SHOTGUN; + self.ltime = time + self.owner.holo_engaged; + + self.th_stand = mirage_run1; + self.th_walk = mirage_run1; + self.th_run = mirage_run1; + self.classname = "mirage"; + + self.takedamage = DAMAGE_NO; + self.angles = self.owner.angles; + self.yaw_speed = 20; + self.proj_ofs=self.view_ofs = '0 0 25'; + + setorigin(self, self.owner.origin); + + FindTarget(); + self.pathentity = self.goalentity; + + self.owner.holo_engaged += 100; + bprint("Mirage engaged\n"); + mirage_run1(); +} + + + + +/* + * Mirage() -- Handles requests to use the Mirage. + */ + +void Mirage() +{ + local entity mirage; + + if(self.classname != "player") + return; + + if(self.holo_engaged == 0) /* Mirage ran out */ + bprint("Mirage not available\n"); + else if(self.holo_engaged >= 100) /* Mirage is engaged */ + remove_mirage(); + else { /* Mirage isn't engaged */ + mirage = spawn(); + mirage.owner = self; + mirage.nextthink = time + 0.05; + mirage.think = init_mirage; + } + } + + + + +/*QUAK-ED item_mirage (0 0 0) (-8 -8 -8) (8 8 8) FLOATING +Gives a player ability to use a Mirage, similar to the "Holoduke" sprite. +Each item is worth 15 seconds. +-------------------------FIELDS------------------------- + +-------------------------------------------------------- +*/ +/* +void item_mirage_touch() +{ + local entity mirage; + + if(other.classname != "player") + return; + if(other.health <= 0) + return; + + remove(self); + sound(other, CHAN_VOICE, "items/artpkup.wav", 1, ATTN_NORM); + stuffcmd(other, "bf"); + bprint("Got Mirage"); + + other.holo_engaged += 15; + if(other.holo_engaged >= 115) + { + while(mirage.owner != other) + { + mirage = find(mirage, classname, "mirage"); + if(mirage == world) + return; + } + mirage.model = "models/player.mdl"; + mirage.ltime += 15; + } + else if(other.holo_engaged > 100) + other.holo_engaged = 100; +} + + +void item_mirage() +{ + precache_model("models/mirage.mdl"); + setmodel(self, "models/mirage.mdl"); + self.touch = item_mirage_touch; + StartItem(); +} + diff --git a/misc.hc b/misc.hc new file mode 100644 index 0000000..5aec1fc --- /dev/null +++ b/misc.hc @@ -0,0 +1,1364 @@ +/* + * $Header: /HexenWorld/Siege/Misc.hc 15 5/31/98 2:59p Mgummelt $ + */ + +/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) +Used as a positional target for spotlights, etc. +*/ +void info_null() +{ + remove(self); +} + +float ROTATE_BREAK = 16; +/* +//============================================================================ + +float POWERPOOL_HEALTH = 1; +float POWERPOOL_EXPERIENCE = 2; +float POWERPOOL_GREENMANA = 4; +float POWERPOOL_BLUEMANA = 8; + + +void power_pool_touch() +{ + if(time < self.ltime) + return; + self.cnt = self.cnt + 1; + if(self.cnt > self.count) + { + self.touch = SUB_Null; + return; + } + + if(self.spawnflags & POWERPOOL_HEALTH) + other.health = other.health + 1; + if(self.spawnflags & POWERPOOL_EXPERIENCE) + other.experience = other.experience + 1; + if(self.spawnflags & POWERPOOL_GREENMANA) + other.greenmana = other.greenmana + 1; + if(self.spawnflags & POWERPOOL_BLUEMANA) + other.bluemana = other.bluemana + 1; + + self.ltime = time + 0.15; +} + +//QUAKED power_pool (0 1 0) ? HEALTH EXPERIENCE GREENMANA BLUEMANA +//Power pool. You can pick whatever combination of benefits you would like. + +void power_pool() +{ + if(!self.spawnflags) + { + remove(self); + return; + } + self.touch = power_pool_touch; + self.solid = SOLID_TRIGGER; + if(!self.count) + self.count = 5; +} +*/ +//============================================================================ + +//Launches a nail in a offset spread (jweier) +void launch_spread(float offset) +{ + local vector offang; + local vector org, vec; + local entity mis; + + org = self.origin; + + offang = vectoangles (self.movedir - org); + offang_y = offang_y + offset * 6; + + makevectors (offang); + + vec = normalize (v_forward); + + vec_z = 0; + + mis = spawn (); + mis.owner = self; + mis.movetype = MOVETYPE_FLYMISSILE; + mis.solid = SOLID_BBOX; + + mis.angles = vectoangles(vec); + + mis.touch = spike_touch; + mis.classname = "spike"; + mis.think = SUB_Remove; + thinktime mis : 6; + setmodel (mis, "models/spike.mdl"); + setsize (mis, VEC_ORIGIN, VEC_ORIGIN); + setorigin (mis, org); + + mis.velocity = vec * 1000; +} + +//============================================================================ + + +//============================================================================ + + +/*QUAKED misc_fireball (0 .5 .8) (-8 -8 -8) (8 8 8) +Lava Balls +*/ + +void fire_fly(); +void fire_touch(); + +void misc_fireball() +{ + precache_model ("models/lavaball.mdl"); + self.classname = "fireball"; + thinktime self : random(5); + self.think = fire_fly; + if (!self.speed) + self.speed == 1000; +} + +void fire_fly() +{ +local entity fireball; + + fireball = spawn(); + fireball.solid = SOLID_TRIGGER; + fireball.movetype = MOVETYPE_TOSS; + fireball.velocity = '0 0 1000'; + fireball.velocity=RandomVector('50 50 0'); + fireball.velocity_z = self.speed + random(200); + fireball.classname = "fireball"; + setmodel (fireball, "models/lavaball.mdl"); + setsize (fireball, '0 0 0', '0 0 0'); + setorigin (fireball, self.origin); + thinktime fireball : 5; + fireball.think = SUB_Remove; + fireball.touch = fire_touch; + + thinktime self : random(3,8); + self.think = fire_fly; +} + +void fire_touch() +{ + T_Damage (other, self, self, 20); + remove(self); +} + + +//============================================================================ + +/* +void() barrel_explode = +{ + self.takedamage = DAMAGE_NO; + self.classname = "explo_box"; + // did say self.owner + T_RadiusDamage (self, self, 160, world); + sound (self, CHAN_VOICE, "weapons/explode.wav", 1, ATTN_NORM); + particle (self.origin, '0 0 0', 75, 255); + + self.origin_z = self.origin_z + 32; + BecomeExplosion (FALSE); +}; + + + +/*QUAK-ED misc_explobox (0 .5 .8) (0 0 0) (32 32 64) +TESTING THING +*/ +/* +void() misc_explobox = +{ + local float oldz; + + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_NONE; + //rj precache_model ("maps/b_explob.bsp"); + setmodel (self, "maps/b_explob.bsp"); + precache_sound ("weapons/explode.wav"); + self.health = 20; + self.th_die = barrel_explode; + self.takedamage = DAMAGE_YES; + + self.origin_z = self.origin_z + 2; + oldz = self.origin_z; + droptofloor(); + if (oldz - self.origin_z > 250) + { + dprint ("item fell out of level at "); + dprint (vtos(self.origin)); + dprint ("\n"); + remove(self); + } +}; +*/ + + + +/*QUAK-ED misc_explobox2 (0 .5 .8) (0 0 0) (32 32 64) +Smaller exploding box, REGISTERED ONLY +* +/* +void() misc_explobox2 = +{ + local float oldz; + + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_NONE; + //rj precache_model2 ("maps/b_exbox2.bsp"); + setmodel (self, "maps/b_exbox2.bsp"); + precache_sound ("weapons/explode.wav"); + self.health = 20; + self.th_die = barrel_explode; + self.takedamage = DAMAGE_YES; + + self.origin_z = self.origin_z + 2; + oldz = self.origin_z; + droptofloor(); + if (oldz - self.origin_z > 250) + { + dprint ("item fell out of level at "); + dprint (vtos(self.origin)); + dprint ("\n"); + remove(self); + } +}; +*/ +//============================================================================ + +float SPAWNFLAG_SUPERSPIKE = 1; +float SPAWNFLAG_LASER = 2; + +/* +void Laser_Touch() +{ + local vector org; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + //sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC); + org = self.origin - 8*normalize(self.velocity); + + if (other.health) + { + SpawnPuff (org, self.velocity*0.2, 15,other); + T_Damage (other, self, self.owner, 15); + } + else + { + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_GUNSHOT); + WriteByte (MSG_BROADCAST, 1); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + } + + remove(self); +} + +void LaunchLaser(vector org, vector vec) +{ + local vector vec; + + vec = normalize(vec); + + newmis = spawn(); + newmis.owner = self; + newmis.movetype = MOVETYPE_FLY; + newmis.solid = SOLID_BBOX; + newmis.effects = EF_DIMLIGHT; + + setmodel (newmis, "models/javproj.mdl"); + setsize (newmis, '0 0 0', '0 0 0'); + + setorigin (newmis, org); + + newmis.velocity = vec * 600; + newmis.angles = vectoangles(newmis.velocity); + + newmis.angles_y = newmis.angles_y + 30; + + thinktime newmis : 5; + newmis.think = SUB_Remove; + newmis.touch = Laser_Touch; +} +*/ +void spikeshooter_use() +{ + + self.enemy = other.enemy; + +/* if (self.spawnflags & SPAWNFLAG_LASER) + { + sound (self, CHAN_VOICE, "enforcer/enfire.wav", 1, ATTN_NORM); + LaunchLaser (self.origin, self.movedir); + } + else + {*/ + sound (self, CHAN_VOICE, "weapons/spike2.wav", 1, ATTN_NORM); + launch_spike (self.origin, self.movedir); + newmis.velocity = self.movedir * 500; + if (self.spawnflags & SPAWNFLAG_SUPERSPIKE) +// newmis.touch = superspike_touch; + newmis.touch = spike_touch; +// } +} + +void shooter_think() +{ + spikeshooter_use (); + thinktime self : self.wait; + //newmis.velocity = self.velocity * 500; +} + +void sprayshooter_use() +{ + sound (self, CHAN_VOICE, "weapons/spike2.wav", 1, ATTN_NORM); + launch_spread(random(10)); +} + +void sprayshooter_think() +{ + sprayshooter_use (); + thinktime self : self.wait; +} + +/*QUAKED trap_spikeshooter_spray (0 .5 .8) (-8 -8 -8) (8 8 8) +When triggered, fires a spike in the direction set in QuakeEd. +*/ +void trap_spikeshooter_spray() +{ + SetMovedir (); + self.use = sprayshooter_use; + precache_sound ("weapons/spike2.wav"); + + if (self.wait == 0) + self.wait = 1; + self.nextthink = self.nextthink + self.wait + self.ltime; + self.think = sprayshooter_think; +} + +/*QUAKED trap_spikeshooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser +When triggered, fires a spike in the direction set in QuakeEd. +Laser is only for REGISTERED. +*/ + +void trap_spikeshooter() +{ + SetMovedir (); + self.use = spikeshooter_use; +/* if (self.spawnflags & SPAWNFLAG_LASER) + { +// precache_model2 ("models/laser.mdl"); + + //precache_sound2 ("enforcer/enfire.wav"); + //precache_sound2 ("enforcer/enfstop.wav"); + } + else*/ + precache_sound ("weapons/spike2.wav"); +} + + +/*QUAKED trap_shooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser +Continuously fires spikes. +"wait" time between spike (1.0 default) +"nextthink" delay before firing first spike, so multiple shooters can be stagered. +*/ +void trap_shooter() +{ + trap_spikeshooter (); + + if (self.wait == 0) + self.wait = 1; + self.nextthink = self.nextthink + self.wait + self.ltime; + self.think = shooter_think; +} + +void () trap_lightning_track = +{ + local vector p1,p2; + local entity targ; + local float len; + + targ = find (world, classname, "player"); // Get ending point + + if (!targ) + { + dprint("No target for lightning"); + return; + } + + if (targ.health <= 0) + { + self.nextthink = -1; + return; + } + + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + p1 = self.origin; + p2 = targ.origin; + + len = vlen(p2 - p1); + + traceline(p1, p2, TRUE, self); + + if (len >= self.aflag || trace_fraction < 1) + { + if (self.wait == -1 || self.spawnflags & 2) + self.nextthink = -1; + else if (self.wait == 1) + thinktime self : random(self.wait,self.wait+2); + else + thinktime self : self.wait; + + return; + } + + do_lightning (self,1,0,4, p1, p2, self.dmg,TE_STREAM_LIGHTNING); + + fx_flash (p2); // Flash of light + + self.think = trap_lightning_track; + + if (self.wait == -1 || self.spawnflags & 2) + self.nextthink = -1; + else if (self.wait == 1) + thinktime self : random(self.wait,self.wait+2); + else + thinktime self : self.wait; +}; + +void () trap_lightning_use = +{ + local vector p1,p2; + local entity targ; + + if (!self.target) + { + dprint("No target for lightning"); + return; + } + + targ = find (world, targetname, self.target); // Get ending point + + if (!targ) + { + dprint("No target for lightning"); + return; + } + + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + p1 = self.origin; + p2 = targ.origin; + + WriteByte (MSG_ALL, SVC_TEMPENTITY); + WriteByte (MSG_ALL, TE_LIGHTNING1); + WriteEntity (MSG_ALL, self); + + WriteCoord (MSG_ALL, p1_x); + WriteCoord (MSG_ALL, p1_y); + WriteCoord (MSG_ALL, p1_z); + + WriteCoord (MSG_ALL, p2_x); + WriteCoord (MSG_ALL, p2_y); + WriteCoord (MSG_ALL, p2_z); + + LightningDamage (p1, p2, self, self.dmg,"lightning"); + + fx_flash (p2); // Flash of light +}; + +/*QUAKED trap_lightning (0 1 1) (-8 -8 -8) (8 8 8) TRACK ONCE +Generates a bolt of lightning which ends at the weather_lightning_end that is the target +-------------------------FIELDS------------------------- +noise - sound generated when lightning appears + 1 - no sound + 2 - lightning (default) + +wait - time between shots +aflag - radius limiter +target - be sure to give this a target fx_lightning_end to hit +dmg - damage this bolt does +-------------------------------------------------------- +*/ +void () trap_lightning = +{ + self.movetype = MOVETYPE_NOCLIP; + self.owner = self; + self.solid = SOLID_NOT; + setorigin (self,self.origin); + setmodel (self,self.model); + setsize (self,self.mins, self.maxs); + + if (!self.noise) + self.noise = "raven/lightng1.wav"; + + if (!self.dmg) + self.dmg = 10; + + if (!self.wait) + self.wait = 1; + + if (!self.aflag) + self.aflag = 500; + + self.ltime = time; + + self.noise = "raven/lightng1.wav"; + precache_sound ("raven/lightng1.wav"); + + if (self.spawnflags & 1) + self.use = trap_lightning_track; + else + self.use = trap_lightning_use; // For triggered lightning +}; + + +/*=============================================================================== + + +=============================================================================== +*/ + + +//void make_bubbles(); +void bubble_remove(); +void bubble_bob(); + +/*QUAK-ED air_bubbles (0 .5 .8) (-8 -8 -8) (8 8 8) + +testing air bubbles +*/ +/* +void air_bubbles() +{ + if (deathmatch) + { + remove (self); + return; + } + precache_model ("models/s_bubble.spr"); + thinktime self : 1; + self.think = make_bubbles; +} + + +void make_bubbles() +{ +local entity bubble; + + bubble = spawn_temp(); + setmodel (bubble, "models/s_bubble.spr"); + setorigin (bubble, self.origin); + bubble.movetype = MOVETYPE_NOCLIP; + bubble.solid = SOLID_NOT; + bubble.velocity = '0 0 15'; + thinktime bubble : 0.5; + bubble.think = bubble_bob; + bubble.touch = bubble_remove; + bubble.classname = "bubble"; + bubble.frame = 0; + bubble.cnt = 0; + setsize (bubble, '-8 -8 -8', '8 8 8'); + thinktime self : random(0.5,1.5); + self.think = make_bubbles; +} +*/ +void() bubble_split = +{ +local entity bubble; + bubble = spawn_temp(); + setmodel (bubble, "models/s_bubble.spr"); + setorigin (bubble, self.origin); + bubble.movetype = MOVETYPE_NOCLIP; + bubble.solid = SOLID_NOT; + bubble.velocity = self.velocity; + thinktime bubble : 0.5; + bubble.think = bubble_bob; + bubble.touch = bubble_remove; + bubble.classname = "bubble"; + bubble.frame = 1; + bubble.cnt = 10; + setsize (bubble, '-8 -8 -8', '8 8 8'); + self.frame = 1; + self.cnt = 10; + if (self.waterlevel != 3) + remove (self); +}; + +void() bubble_remove = +{ + if (other.classname == self.classname) + { +// dprint ("bump"); + return; + } + remove(self); +}; + + +void() bubble_bob = +{ +local float rnd1, rnd2, rnd3; + +local float waterornot; + waterornot=pointcontents(self.origin); + if (waterornot!=CONTENT_WATER&&waterornot!=CONTENT_SLIME) + remove(self); + self.cnt = self.cnt + 1; + if (self.cnt == 4) + bubble_split(); + if (self.cnt == 20) + remove(self); + + rnd1 = self.velocity_x + random(-10,10); + rnd2 = self.velocity_y + random(-10,10); + rnd3 = self.velocity_z + random(10,20); + + if (rnd1 > 10) + rnd1 = 5; + if (rnd1 < -10) + rnd1 = -5; + + if (rnd2 > 10) + rnd2 = 5; + if (rnd2 < -10) + rnd2 = -5; + + if (rnd3 < 10) + rnd3 = 15; + if (rnd3 > 30) + rnd3 = 25; + + self.velocity_x = rnd1; + self.velocity_y = rnd2; + self.velocity_z = rnd3; + + thinktime self : 0.5; + self.think = bubble_bob; +}; + + +/*~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~> +~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~*/ + +/*QUAK-ED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8) +Just for the debugging level. Don't use +*/ +/* +void viewthing() +{ + self.movetype = MOVETYPE_NONE; + self.solid = SOLID_NOT; +// precache_model ("models/player.mdl"); +// setmodel (self, "models/player.mdl"); +} +*/ + + +/* +============================================================================== + +SIMPLE BMODELS + +============================================================================== +*/ + +void() func_wall_use = +{ // change to alternate textures + self.frame = 1 - self.frame; +}; + +/*QUAKED func_wall (0 .5 .8) ? TRANSLUCENT +This is just a solid wall if not inhibitted +TRANSLUCENT - makes it see-through +abslight = how bright to make it +*/ +void func_wall() +{ + self.angles = '0 0 0'; + self.movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything + self.solid = SOLID_BSP; + self.classname="solid wall"; + self.use = func_wall_use; + setmodel (self, self.model); + if(self.spawnflags&1) + self.drawflags=DRF_TRANSLUCENT; + if(self.abslight) + self.drawflags(+)MLS_ABSLIGHT; +} + + +/*QUAKED func_illusionary (0 .5 .8) ? TRANSLUCENT LIGHT +A simple entity that looks solid but lets you walk through it. +*/ +void func_illusionary() +{ + if (self.spawnflags & 1) + self.drawflags (+) DRF_TRANSLUCENT; + + if (self.abslight) + self.drawflags (+) MLS_ABSLIGHT; + + if (self.spawnflags & 2) + self.drawflags (+) MLS_ABSLIGHT; + + self.classname="illusionary wall"; + self.angles = '0 0 0'; + self.movetype = MOVETYPE_NONE; + self.solid = SOLID_NOT; + setmodel (self, self.model); + makestatic (self); +} + +//============================================================================ + +/* +void noise_think() +{ + thinktime self : 0.5; + //sound (self, 1, "enforcer/enfire.wav", 1, ATTN_NORM); + //sound (self, 2, "enforcer/enfstop.wav", 1, ATTN_NORM); +// sound (self, 3, "enforcer/sight1.wav", 1, ATTN_NORM); +// sound (self, 4, "enforcer/sight2.wav", 1, ATTN_NORM); +// sound (self, 5, "enforcer/sight3.wav", 1, ATTN_NORM); +// sound (self, 6, "enforcer/sight4.wav", 1, ATTN_NORM); +// sound (self, 7, "enforcer/pain1.wav", 1, ATTN_NORM); +} +*/ + +/*QUAKED misc_noisemaker (1 0.5 0) (-10 -10 -10) (10 10 10) +For optimzation testing, starts a lot of sounds. +*/ +/*void misc_noisemaker() +{ + //precache_sound2 ("enforcer/enfire.wav"); + //precache_sound2 ("enforcer/enfstop.wav"); +// precache_sound2 ("enforcer/sight1.wav"); +// precache_sound2 ("enforcer/sight2.wav"); +// precache_sound2 ("enforcer/sight3.wav"); +// precache_sound2 ("enforcer/sight4.wav"); +// precache_sound2 ("enforcer/pain1.wav"); +// precache_sound2 ("enforcer/pain2.wav"); +// precache_sound2 ("enforcer/death1.wav"); +// precache_sound2 ("enforcer/idle1.wav"); + + thinktime self : random(0.1,1.1); + self.think = noise_think; +} +*/ + +/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS BREAK GRADUAL TOGGLE_REVERSE KEEP_START +You need to have an origin brush as part of this entity. The +center of that brush will be the point around which it is rotated. +It will rotate around the Z axis by default. You can +check either the X_AXIS or Y_AXIS box to change that. +BREAK makes the brush breakable +REVERSE will cause the it to rotate in the opposite direction. +GRADUAL will make it slowly speed up and slow down. +TOGGLE_REVERSE will make it go in the other direction next time it's triggered +KEEP_START means it will return to it's starting position when turned off + +"speed" determines how fast it moves; default value is 100. +"dmg" damage to inflict when blocked (2 default) +"lifetime" this will make it stop after a while, then start up again after "wait". Default is staying on. +"wait" if it has a lifetime, this is how long it will wait to start up again. default is 3 seconds. +"thingtype" type of brush (if breakable - default is wood) +"health" (if breakable - default is 25) +"abslight" - to set the absolute light level +"anglespeed" - If using GRADUAL, this will determine how fast the speed up and down will occur. 1 will be very slow, 100 will be instant. (Default is 10) + +thingtype - type of chunks and sprites it will generate + 0 - glass (default) + 1 - stone + 2 - wood + 3 - metal + 4 - flesh + +health - amount of damage item can take. Default is based on thingtype + glass - 25 + stone - 75 + wood - 50 + metal - 100 + flesh - 30 +*/ +void() rotating_use; +void() rotating_touch; +void rotate_wait (void) +{ + thinktime self : 10000000000; +} + +void rotate_reset (void) +{ + if(self.wait) + { + self.think=rotating_use; + thinktime self : self.wait; + } + else + { + self.think=SUB_Null; + self.nextthink=-1; + } +} + +void rotate_wait_startpos (void) +{ + if(self.angles==self.o_angle) + { + self.avelocity='0 0 0'; + rotate_reset(); + } + else + thinktime self : 0.05; +} + +void rotate_slowdown (void) +{ + self.level-=(self.speed/self.anglespeed); + if((self.dmg==-1||self.dmg==666)&&self.level<100) + self.touch=SUB_Null; + + if(self.level<1||(self.level<=self.speed/self.anglespeed&&self.spawnflags&KEEP_START)) + { + if(self.spawnflags&KEEP_START) + { + self.think=rotate_wait_startpos; + thinktime self : 0; + } + else + { + self.avelocity='0 0 0'; + rotate_reset(); + } + } + else + { + self.avelocity=self.movedir*self.level; + self.think=rotate_slowdown; + thinktime self : 0.01; + } +} + +void rotate_startup (void) +{ + self.level+=(self.speed/self.anglespeed); + if((self.dmg==-1||self.dmg==666)&&self.level>=100&&self.touch==SUB_Null) + self.touch=rotating_touch; + + if(self.pain_finished<=time&&self.lifetime) + { + self.think=rotating_use; + thinktime self : 0; + return; + } + + if(self.leveltime&&self.lifetime) + { + self.think=rotating_use; + thinktime self : self.pain_finished; + return; + } + else + { + self.think=rotate_wait; + thinktime self : 10000000000; + } + } +} + +void rotating_use() +{ + if (self.avelocity != '0 0 0') + { + if(!self.spawnflags&GRADUAL) + { + self.avelocity='0 0 0'; + rotate_reset(); + } + else if(self.think==rotate_slowdown) + return; + else + { + sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + self.think=rotate_slowdown; + thinktime self : 0; + } + } + else + { + if(self.lifetime) + self.pain_finished=time+self.lifetime; + if(self.spawnflags&TOGGLE_REVERSE) + self.movedir= self.movedir*-1; + if(!self.spawnflags&GRADUAL) + { + self.avelocity = self.movedir * self.speed; + self.think=rotating_use; + thinktime self : 10000000000; + } + else + { + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.think=rotate_startup; + thinktime self : 0; + } + } +} + +void rotating_damage (entity chopped_liver) +{ + if(self.dmg==666) + { + if(chopped_liver.classname=="player"&&chopped_liver.flags2&FL_ALIVE) + { + chopped_liver.decap=TRUE; + T_Damage (chopped_liver, self, self, chopped_liver.health+300); + } + else + T_Damage (chopped_liver, self, self, chopped_liver.health+50); + } + else if(self.dmg==-1&&chopped_liver.health) + { + float damg; + chopped_liver.deathtype="chopped"; + damg=vlen(self.avelocity); + T_Damage (chopped_liver, self, self, damg); + } +} + +void rotating_touch() +{ + if(!other.takedamage) + return; + rotating_damage(other); +} + +void rotating_blocked (void) +{ + if(!other.takedamage) + return; + + rotating_damage(other); + + if(other.health>100&&!other.flags2&FL_ALIVE)//allow for blockage + { + self.avelocity='0 0 0'; + self.level=0; + self.touch=SUB_Null; + self.think=rotating_use; + thinktime self : self.wait; + } +} + +void func_rotating() +{ + // set the axis of rotation + if (self.spawnflags & 4) + self.movedir = '0 0 1'; + else if (self.spawnflags & 8) + self.movedir = '1 0 0'; + else + self.movedir = '0 1 0'; + + // check for reverse rotation + if (self.spawnflags & 2) + self.movedir = self.movedir * -1; + + if(self.spawnflags&TOGGLE_REVERSE) + self.movedir = self.movedir * -1; + + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + self.classname="rotating non-door"; + setorigin (self, self.origin); + setmodel (self, self.model); + + self.use = rotating_use; + self.blocked = rotating_blocked; + self.touch=SUB_Null; + + if (!self.speed) + self.speed = 100; + + if(!self.anglespeed) + self.anglespeed = 10; + + if (self.dmg==0) + self.dmg = 2; + + if(self.lifetime) + if(!self.wait) + self.wait=3; + +// self.noise1 = "doors/hydro1.wav"; +// self.noise2 = "doors/hydro2.wav"; + +// precache_sound ("doors/hydro1.wav"); +// precache_sound ("doors/hydro2.wav"); + + if (self.abslight) + self.drawflags(+)MLS_ABSLIGHT; + + if (self.spawnflags & ROTATE_BREAK) + { + if (!self.thingtype) + self.thingtype = THINGTYPE_WOOD; + if (!self.health) + { + if ((self.thingtype == THINGTYPE_GLASS) || (self.thingtype == THINGTYPE_CLEARGLASS)) + self.health = 25; + else if ((self.thingtype == THINGTYPE_GREYSTONE) || (self.thingtype == THINGTYPE_BROWNSTONE)||self.thingtype==THINGTYPE_DIRT) + self.health = 75; + else if (self.thingtype == THINGTYPE_WOOD) + self.health = 50; + else if (self.thingtype == THINGTYPE_METAL) + self.health = 100; + else if (self.thingtype == THINGTYPE_FLESH) + self.health = 30; + else + self.health = 25; + } + self.takedamage = DAMAGE_YES; + self.th_die = chunk_death; + } + + if(self.spawnflags&KEEP_START) + self.o_angle=self.angles; + + if (self.spawnflags & 1) + self.use(); + + if (self.flags2) + { + self.touch = rotating_touch; + self.flags2=FALSE; + } +} + +/*QUAK-ED trigger_fan_blow (0 .5 .8) ? +Will blow anything in the direction of the func_rotating it's targeted by. +Note that clockwise rotation pulls you towards it, counterclockwise pushes you away- func_rotating design should match this. +To use, target this trigger with with the func_rotating (do NOT target the func_rotating with the trigger!!!). +Then place this trigger so that it covers both front and back of the "fan" and extend it as far as you want it to have influence. +*/ + +void trigger_find_owner (void) +{ +entity found; + found=find(world,target,self.targetname); + if(found==world) + remove(self); + else + self.owner=found; +} +/* +void trigger_fan_blow_touch (void) +{ +vector blowdir, org; +float blowhard, blowdist; + if(other==self.owner) + return; + + if(self.owner.origin=='0 0 0') + org=(self.owner.absmin+self.owner.absmax)*0.5; + else + org=self.owner.origin; + + if(self.owner.avelocity_x!=0) + { +//FIXME: Need to cheat here? dilute avelocity? + blowhard=self.owner.avelocity_x/3; + blowdir = '0 1 0'; + blowdist = fabs(org_y - other.origin_y); + } + else if(self.owner.avelocity_y!=0) + { + blowhard = self.owner.avelocity_y; + blowdir = '0 0 1'; + blowdist = fabs(org_z - other.origin_z); + } + else if(self.owner.avelocity_z!=0) + { +//FIXME: Need to cheat here? dilute avelocity? + blowhard=self.owner.avelocity_z/3; + blowdir = '1 0 0'; + blowdist = fabs(org_x - other.origin_x); + } + else + return; + if(blowdist<100) + blowdist=0; + + if(blowhard>0) + { + blowhard-=blowdist; + if(blowhard<=0) + return; + } + else + { + blowhard+=blowdist; + if(blowhard>=0) + return; + } + blowhard/=10; + +//FIXME: Factor in mass? + blowdir*=blowhard; +//FIXME: Need to cheat here? Pull down much faster? + if(blowdir_z<0) + blowdir*=10; +//FIXME: Will actually slow someone down if their already moving in this direction! + if(other.velocity!=blowdir) + { + other.velocity+=blowdir; + UpdateMissileVelocity(other); + } +// if(!other.flags&FL_ONGROUND) +// { +// if(pointcontents(other.origin)==CONTENT_EMPTY&&other.movetype!=MOVETYPE_FLY&&other.movetype!=MOVETYPE_FLYMISSILE&&other.movetype!=MOVETYPE_BOUNCEMISSILE) +// other.velocity_z-=60;//FIXME: calculate in gravity too +// } +// else + if(other.flags&FL_ONGROUND) + { + other.flags(-)FL_ONGROUND; + if(other.velocity_z==0) + other.velocity_z+=7; + } +} + +void trigger_fan_blow (void) +{ + InitTrigger(); + self.touch=trigger_fan_blow_touch; + self.think=trigger_find_owner; + thinktime self : 0.1; +} +*/ + +void() angletrigger_done = +{ + self.level = FALSE; +}; + +void() angletrigger_blocked = +{ + T_Damage (other, self, self, self.dmg); +}; + +void() angletrigger_use = +{ +vector newvect; + + if (self.level) + return; + else + self.level = TRUE; + + if(self.angles_x>=360) + self.angles_x-=360; + else if(self.angles_x<=-360) + self.angles_x+=360; + if(self.angles_y>=360) + self.angles_y-=360; + else if(self.angles_y<=-360) + self.angles_y+=360; + if(self.angles_z>=360) + self.angles_z-=360; + else if(self.angles_z<=-360) + self.angles_z+=360; + newvect = self.movedir * self.cnt; + + if (self.angles + newvect == self.mangle) + { + self.check_ok = TRUE; + SUB_UseTargets(); + } + else if (self.check_ok) + { + self.check_ok = FALSE; + SUB_UseTargets(); + } + + SUB_CalcAngleMove(self.angles + newvect, self.speed, angletrigger_done); +}; + +/*QUAKED func_angletrigger (0 .5 .8) ? REVERSE X_AXIS Y_AXIS +Rotates at certain intervals, and fires off when a set angle is met + +mangle = desired angle to trigger at (relative to the world!) +cnt = degrees to turn each move +dmg = damage if blocked +*/ + +void() func_angletrigger = +{ + + // set the axis of rotation + if (self.spawnflags & 2) + self.movedir = '0 0 1'; + else if (self.spawnflags & 4) + self.movedir = '1 0 0'; + else + self.movedir = '0 1 0'; + + // check for clockwise rotation + if (self.spawnflags & 1) + self.movedir = self.movedir*-1; + + self.pos1 = self.angles; + self.pos2 = self.angles + self.movedir * self.cnt; + + self.max_health = self.health; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + self.classname = "angletrigger"; + + if (self.abslight) + self.drawflags(+)MLS_ABSLIGHT; + + if (!self.speed) + self.speed = 100; + if (self.wait==0) + self.wait = 1; + if (!self.dmg) + self.dmg = 2; + +/* + precache_sound ("doors/hydro1.wav"); + precache_sound ("doors/hydro2.wav"); + precache_sound ("doors/basetry.wav"); + precache_sound ("doors/baseuse.wav"); + self.noise2 = "doors/hydro1.wav"; + self.noise1 = "doors/hydro2.wav"; + self.noise3 = "doors/basetry.wav"; + self.noise4 = "doors/baseuse.wav"; +*/ + self.blocked = angletrigger_blocked; + self.use = angletrigger_use; + + if (!self.targetname) + self.touch = angletrigger_use; + + self.inactive = FALSE; +}; + +void shish_ka_bob (entity loser) +{ + T_Damage(loser,self,self,other.health+random(10,20)); + sound(other,CHAN_BODY,"player/gib1.wav",1,ATTN_NORM); + //leave behind something? Drip blood? Sound? +} + +void velocity_damage () +{ +float impact; + if(!other.takedamage) + return; + if(other.health<=0) + return; + if(other.last_onground+0.25>time) + return; + if(other.movetype==MOVETYPE_FLY) + return; + if(self.movedir!='0 0 0') + if(normalize(other.velocity)*self.movedir<0) + return; + + impact=vlen(other.velocity)*other.mass/10; + impact*=self.dmg; + +//FIXME: Skewer them +/* + if(other.healthtime) + return; + starteffect(CE_RIPPLE, self.origin,'0 0 0',HX_FRAME_TIME); + self.attack_finished=time+self.wait; +} + +/*QUAKED misc_ripples (0 0 1) (-4 -4 0) (4 4 8) +When used, starts a ripple +"wait" - shortest time between two ripples +*/ +void misc_ripples() +{ + if(!self.wait) + self.wait = 0.1; + self.use=make_ripple; +} + diff --git a/models.hc b/models.hc new file mode 100644 index 0000000..914a87b --- /dev/null +++ b/models.hc @@ -0,0 +1,588 @@ +/* + * $Header: /HexenWorld/Siege/MODELS.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +=============================================================================== + +WORLD WEAPONS + +=============================================================================== +*/ + +$modelname g_shot +$cd id1/models/g_shot +$origin 0 0 -24 +$flags 8 // client side rotate +$base base +$skin skin +$frame shot1 + + +$modelname g_nail +$cd id1/models/g_nail +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + + +$modelname g_nail2 +$cd id1/models/g_nail2 +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot2 + + +$modelname g_rock +$cd id1/models/g_rock +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + + +$modelname g_rock2 +$cd id1/models/g_rock2 +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + +$modelname g_light +$cd id1/models/g_light +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + +/* +=============================================================================== + +VIEW WEAPONS + +=============================================================================== +*/ + +$modelname v_axe +$cd id1/models/v_axe +$origin 0 5 54 +$base base +$skin skin +$frame frame1 frame2 frame3 frame4 frame5 frame6 frame7 frame8 frame9 + + +$modelname v_shot +$cd id1/models/v_shot +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 + + +$modelname v_shot2 +$cd id1/models/v_shot2 +$origin 0 0 56 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 + + +$modelname v_rock2 +$cd id1/models/v_rock2 +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot6 + + +$modelname v_rock +$cd id1/models/v_rock +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 + + +$modelname v_nail2 +$cd id1/models/v_nail2 +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 shot8 shot9 + + +$modelname v_nail +$cd id1/models/v_nail +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 shot8 shot9 + +$modelname v_light +$cd id1/models/v_light +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 + + +/* +=============================================================================== + +ITEMS + +=============================================================================== +*/ + +$modelname w_g_key +$cd id1/models/w_g_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname w_s_key +$cd id1/models/w_s_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname m_g_key +$cd id1/models/m_g_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname m_s_key +$cd id1/models/m_s_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname b_g_key +$cd id1/models/b_g_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname b_s_key +$cd id1/models/b_s_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + + +$modelname quaddama +$cd id1/models/quaddama +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname invisibl +$cd id1/models/invisibl +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname invulner +$flags 8 // client side rotate +$cd id1/models/invulner +$base base +$skin skin +$frame frame1 + +//modelname jetpack +//cd id1/models/jetpack +//flags 8 // client side rotate +//base base +//skin skin +//frame frame1 + +$modelname cube +$cd id1/models/cube +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname suit +$cd id1/models/suit +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname boots +$cd id1/models/boots +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end1 +$cd id1/models/end1 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end2 +$cd id1/models/end2 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end3 +$cd id1/models/end3 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end4 +$cd id1/models/end4 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + + +/* +=============================================================================== + +GIBS + +=============================================================================== +*/ + +$modelname gib1 +$cd id1/models/gib1 +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + + +// torso +$modelname gib2 +$cd id1/models/gib2 +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname gib3 +$cd id1/models/gib3 +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + + +// heads + +$modelname h_player +$cd id1/models/h_player +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_dog +$cd id1/models/h_dog +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_mega +$cd id1/models/h_mega +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_guard +$cd id1/models/h_guard +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_wizard +$cd id1/models/h_wizard +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_knight +$cd id1/models/h_knight +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_hellkn +$cd id1/models/h_hellkn +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_zombie +$cd id1/models/h_zombie +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_shams +$cd id1/models/h_shams +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_shal +$cd id1/models/h_shal +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_ogre +$cd id1/models/h_ogre +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_demon +$cd id1/models/h_demon +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +/* +=============================================================================== + +MISC + +=============================================================================== +*/ + +$modelname armor +$cd id1/models/armor +$flags 8 // client side rotate +$origin 0 0 -8 +$base base +$skin skin +$skin skin2 +$skin skin3 +$frame armor + +$modelname s_light // shambler lightning ready +$cd id1/models/s_light +$origin 0 0 24 +$base base +$skin skin +$frame frame1 frame2 frame3 + +$modelname bolt3 // lightning towar bolts +$cd id1/models/bolt2 +$origin 0 0 0 +$base base +$scale 4 +$skin skin +$frame light + +$modelname bolt2 +$cd id1/models/bolt2 +$origin 0 0 0 +$base base +$skin skin +$frame light + +$modelname bolt +$cd id1/models/bolt +$origin 0 0 0 +$base light +$skin light +$frame light + +$modelname laser +$cd id1/models/laser +$base base +$skin skin +$scale 2 +$frame frame1 + +$modelname flame // with torch +$cd id1/models/flame +$origin 0 0 12 +$base base +$skin skin +$framegroupstart +$frame flame1 0.1 +$frame flame2 0.1 +$frame flame3 0.1 +$frame flame4 0.1 +$frame flame5 0.1 +$frame flame6 0.1 +$framegroupend + +$modelname flame2 // standing flame, no torch +$cd id1/models/flame2 +$origin 0 0 12 +$base base +$skin skin +$framegroupstart +$frame flame1 0.1 +$frame flame2 0.1 +$frame flame3 0.1 +$frame flame4 0.1 +$frame flame5 0.1 +$frame flame6 0.1 +$framegroupend +$framegroupstart +$frame flameb1 +$frame flameb2 +$frame flameb3 +$frame flameb4 +$frame flameb5 +$frame flameb6 +$frame flameb7 +$frame flameb8 +$frame flameb9 +$frame flameb10 +$frame flameb11 +$framegroupend + +$modelname zom_gib +$cd id1/models/zom_gib +$flags 32 // EF_ZOMGIB +$base base +$skin skin +$frame frame1 + +$modelname eyes +$cd id1/models/eyes +$origin 0 0 -24 +$base base +$skin skin +$frame frame1 + +$modelname spike +$cd id1/models/spike +$origin 0 0 0 +$base spike +$skin skin +$frame spike + +$modelname s_spike +$cd id1/models/s_spike +$origin 0 0 0 +$base spike +$skin skin +$frame spike + +$modelname v_spike +$cd id1/models/v_spike +$flags 128 // EF_TRACER3 +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname w_spike +$cd id1/models/w_spike +$flags 16 // EF_TRACER +$origin 0 0 0 +$base base +$skin skin +$framegroupstart +$frame frame1 0.1 +$frame frame2 0.1 +$frame frame3 0.1 +$frame frame4 0.1 +$framegroupend + +$modelname k_spike +$cd id1/models/k_spike +$flags 64 // EF_TRACER2 +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname backpack +$cd id1/models/backpack +$flags 8 // EF_ROTATE +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname grenade +$cd id1/models/grenade2 +$flags 2 // EF_GRENADE +$origin 0 0 0 +$base base +$skin skin +$frame grenade + +$modelname missile +$cd id1/models/missile +$flags 1 // EF_ROCKET +$origin 0 0 0 +$base base +$skin skin +$frame missile + +$modelname lavaball +$cd id1/models/lavaball +$flags 1 // EF_ROCKET +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname teleport +$cd id1/models/teleport +$origin 0 0 24 +$base base +$skin skin +$frame frame1 + diff --git a/monsters.hc b/monsters.hc new file mode 100644 index 0000000..24e0503 --- /dev/null +++ b/monsters.hc @@ -0,0 +1,328 @@ +/* + * $Header: /HexenWorld/Siege/MONSTERS.hc 4 5/25/98 1:39p Mgummelt $ + */ +/* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */ + +// name =[framenum, nexttime, nextthink] {code} +// expands to: +// name () +// { +// self.frame=framenum; +// self.nextthink = time + nexttime; +// self.think = nextthink +// +// }; + + +/* +================ +monster_use + +Using a monster makes it angry at the current activator +================ +*/ +void() monster_use = +{ + if (self.enemy) + return; + if (self.health <= 0) + return; + if (activator.items & IT_INVISIBILITY) + return; + if (activator.flags & FL_NOTARGET) + return; + if (activator.classname != "player") + return; + + if(self.classname=="monster_mezzoman"&&!visible(activator)&&!self.monster_awake) + { + self.enemy=activator; + mezzo_choose_roll(activator); + return; + } +// delay reaction so if the monster is teleported, its sound is still +// heard + else + { + self.enemy = activator; + thinktime self : 0.1; + self.think = FoundTarget; + } +}; + +/* +================ +monster_death_use + +When a mosnter dies, it fires all of its targets with the current +enemy as activator. +================ +*/ +void() monster_death_use = +{ +// fall to ground + self.flags(-)FL_FLY; + self.flags(-)FL_SWIM; + + if (!self.target) + return; + + activator = self.enemy; + SUB_UseTargets (); +}; + + +//============================================================================ + +void() walkmonster_start_go = +{ + if(!self.touch) + self.touch=obj_push; + + if(!self.spawnflags&NO_DROP) + { + self.origin_z = self.origin_z + 1; // raise off floor a bit + droptofloor(); + if (!walkmove(0,0, FALSE)) + { + if(self.flags2&FL_SUMMONED) + remove(self); + else + { + dprint ("walkmonster in wall at: "); + dprint (vtos(self.origin)); + dprint ("\n"); + } + } + if(self.model=="model/spider.mdl"||self.model=="model/scorpion.mdl") + pitch_roll_for_slope('0 0 0'); + } + + if(!self.ideal_yaw) + { +// dprint("no preset ideal yaw\n"); + self.ideal_yaw = self.angles * '0 1 0'; + } + + if (!self.yaw_speed) + self.yaw_speed = 20; + + if(self.view_ofs=='0 0 0') + self.view_ofs = '0 0 25'; + + if(self.proj_ofs=='0 0 0') + self.proj_ofs = '0 0 25'; + + if(!self.use) + self.use = monster_use; + + if(!self.flags&FL_MONSTER) + self.flags(+)FL_MONSTER; + + if(self.flags&FL_MONSTER&&self.classname=="player_sheep") + self.flags(-)FL_MONSTER; + + if (self.target) + { + self.goalentity = self.pathentity = find(world, targetname, self.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.pathentity) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror +/* if(self.spawnflags&PLAY_DEAD&&self.th_possum!=SUB_Null) + { + self.think=self.th_possum; + thinktime self : 0; + } + else +*/ + if (self.pathentity.classname == "path_corner") + self.th_walk (); + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + else + { +/* if(self.spawnflags&PLAY_DEAD&&self.th_possum!=SUB_Null) + { + self.think=self.th_possum; + thinktime self : 0; + } + else + { +*/ + self.pausetime = 99999999; + self.th_stand (); +// } + } + +// spread think times so they don't all happen at same time + self.nextthink+=random(0.5); +}; + +void() walkmonster_start = +{ +// delay drop to floor to make sure all doors have been spawned +// spread think times so they don't all happen at same time + self.takedamage=DAMAGE_YES; + self.flags2(+)FL_ALIVE; + + if(self.scale<=0) + self.scale=1; + + self.nextthink+=random(0.5); + self.think = walkmonster_start_go; + total_monsters = total_monsters + 1; +}; + + + +/* +void() flymonster_start_go = +{ + self.takedamage = DAMAGE_YES; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + + if(self.view_ofs=='0 0 0'); + self.view_ofs = '0 0 24'; + if(self.proj_ofs=='0 0 0'); + self.proj_ofs = '0 0 24'; + + self.use = monster_use; + + self.flags(+)FL_FLY; + self.flags(+)FL_MONSTER; + + if(!self.touch) + self.touch=obj_push; + + if (!walkmove(0,0, FALSE)) + { + dprint ("flymonster in wall at: "); + dprint (vtos(self.origin)); + dprint ("\n"); + } + + if (self.target) + { + self.goalentity = self.pathentity = find(world, targetname, self.target); + if (!self.pathentity) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror +// if(self.spawnflags&PLAY_DEAD&&self.th_possum!=SUB_Null) +// { +// self.think=self.th_possum; +// thinktime self : 0; +// } +// else + + if (self.pathentity.classname == "path_corner") + self.th_walk (); + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + else + { +// if(self.spawnflags&PLAY_DEAD&&self.th_possum!=SUB_Null) +// { +// self.think=self.th_possum; +// thinktime self : 0; +// } +// else +// { + + self.pausetime = 99999999; + self.th_stand (); +// } + } +}; + +void() flymonster_start = +{ +// spread think times so they don't all happen at same time + self.takedamage=DAMAGE_YES; + self.flags2(+)FL_ALIVE; + self.nextthink+=random(0.5); + self.think = flymonster_start_go; + total_monsters = total_monsters + 1; +}; + +void() swimmonster_start_go = +{ + if (deathmatch) + { + remove(self); + return; + } + + if(!self.touch) + self.touch=obj_push; + + self.takedamage = DAMAGE_YES; + total_monsters = total_monsters + 1; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + + if(self.view_ofs=='0 0 0'); + self.view_ofs = '0 0 10'; + if(self.proj_ofs=='0 0 0'); + self.proj_ofs = '0 0 10'; + + self.use = monster_use; + + self.flags(+)FL_SWIM; + self.flags(+)FL_MONSTER; + + if (self.target) + { + self.goalentity = self.pathentity = find(world, targetname, self.target); + if (!self.pathentity) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + +// spread think times so they don't all happen at same time + self.nextthink+=random(0.5); +}; + +void() swimmonster_start = +{ +// spread think times so they don't all happen at same time + self.takedamage=DAMAGE_YES; + self.flags2(+)FL_ALIVE; + self.nextthink+=random(0.5); + self.think = swimmonster_start_go; + total_monsters = total_monsters + 1; +}; +*/ + diff --git a/mummy.hc b/mummy.hc new file mode 100644 index 0000000..03c2c23 --- /dev/null +++ b/mummy.hc @@ -0,0 +1,1051 @@ +/* + * $Header: /HexenWorld/Siege/mummy.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\mummy\mummy.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\mummy +$origin 0 0 0 +$base BASE-F skin +$skin skin +$flags 0 + + +// DEATH : FRAMES 1 - 13, no arms, one leg +$frame mdeath1 mdeath2 mdeath3 mdeath4 mdeath5 +$frame mdeath6 mdeath7 mdeath8 mdeath9 mdeath10 +$frame mdeath11 mdeath12 mdeath13 + +// STAFF ATTACK : FRAMES 14 - 37, both arms, both legs +$frame mstafA1 mstafA2 mstafA3 mstafA4 mstafA5 +$frame mstafA6 mstafA7 mstafA8 mstafA9 mstafA10 +$frame mstafA11 mstafA12 mstafA13 mstafA14 mstafA15 +$frame mstafA16 mstafA17 mstafA18 mstafA19 mstafA20 +$frame mstafA21 mstafA22 mstafA23 mstafA24 + +// MELEE SWING : FRAMES 38 - 47, no arms, both legs, swings his stump at enemy +$frame mswingC1 mswingC2 mswingC3 mswingC4 mswingC5 +$frame mswingC6 mswingC7 mswingC8 mswingC9 mswingC10 + +// MELEE SWING : FRAMES 48 - 65, both arms and legs, swings his staff at enemy +$frame mswngA1 mswngA2 mswngA3 mswngA4 mswngA5 +$frame mswngA6 mswngA7 mswngA8 mswngA9 mswngA10 +$frame mswngA11 mswngA12 mswngA13 mswngA14 mswngA15 +$frame mswngA16 mswngA17 mswngA18 + +// MELEE SWING : FRAMES 66 - 83, one arm, both legs, swings his staff at enemy +$frame mswngB1 mswngB2 mswngB3 mswngB4 mswngB5 +$frame mswngB6 mswngB7 mswngB8 mswngB9 mswngB10 +$frame mswngB11 mswngB12 mswngB13 mswngB14 mswngB15 +$frame mswngB16 mswngB17 mswngB18 + +// WALKING: frames 84 - 97, both arms and both legs +$frame mwalkA1 mwalkA2 mwalkA3 mwalkA4 mwalkA5 +$frame mwalkA6 mwalkA7 mwalkA8 mwalkA9 mwalkA10 +$frame mwalkA11 mwalkA12 mwalkA13 mwalkA14 + +// WALKING: frames 98 - 113, one arm and both legs +$frame mwalkB1 mwalkB2 mwalkB3 mwalkB4 mwalkB5 +$frame mwalkB6 mwalkB7 mwalkB8 mwalkB9 mwalkB10 +$frame mwalkB11 mwalkB12 mwalkB13 mwalkB14 mwalkB15 +$frame mwalkB16 + +// WALKING: frames 114 - 131, no arms, both legs +$frame mwalkC1 mwalkC2 mwalkC3 mwalkC4 mwalkC5 +$frame mwalkC6 mwalkC7 mwalkC8 mwalkC9 mwalkC10 +$frame mwalkC11 mwalkC12 mwalkC13 mwalkC14 mwalkC15 +$frame mwalkC16 mwalkC17 mwalkC18 + +// 132 - 147 +$frame shoota1 shoota2 shoota3 shoota4 shoota5 +$frame shoota6 shoota7 shoota8 shoota9 shoota10 +$frame shoota11 shoota12 shoota13 shoota14 shoota15 +$frame shoota16 + +// +$frame shootb1 shootb2 shootb3 shootb4 shootb5 +$frame shootb6 shootb7 shootb8 shootb9 shootb10 +$frame shootb11 shootb12 shootb13 shootb14 shootb15 +$frame shootb16 + +// +$frame staffb1 staffb2 staffb3 staffb4 staffb5 +$frame staffb6 staffb7 staffb8 staffb9 staffb10 +$frame staffb11 staffb12 staffb13 staffb14 staffb15 +$frame staffb16 staffb17 staffb18 staffb19 staffb20 +$frame staffb21 staffb22 staffb23 staffb24 staffb25 +$frame staffb26 staffb27 + +// +$frame crawl1 crawl2 crawl3 crawl4 crawl5 +$frame crawl6 crawl7 crawl8 crawl9 crawl10 +$frame crawl11 crawl12 crawl13 crawl14 + + + + + +// What parts are gone from the mummy +float MUMMY_NONE = 0; // None +float MUMMY_LARM = 1; // Left arm is gone +float MUMMY_RARM = 2; // Left and Right arm are gone +float MUMMY_LEG = 3; // Left and Right arm are gone,Left leg is gone + +float MUMMY_WAVER = 1; +float MUMMY_DOWN = 2; + +void mummyrun(void); +void mummywalk(void); +void mummymelee(void); + +/* +============ +pmissile_touch - missile1 hit something. Hurt it +============ +*/ +void mummissile_touch (void) +{ + float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + pmissile_gone(); + return; + } + + damg = random(5,10); + if (other.health) + T_Damage (other, self, self.owner, damg ); + + sound (self, CHAN_BODY, "weapons/expsmall.wav", 1, ATTN_NORM); + self.origin = self.origin - 8*normalize(self.velocity); + + CreateFireCircle(self.origin - (v_forward * 8)); + + self.effects = EF_NODRAW; + self.solid = SOLID_NOT; +// self.nextthink = time + .5; // So explosion sound can finish out + thinktime self : .5; + + self.think = pmissile_gone; +} + + +void mflame1_runup (void) [++ 0 .. 16 ] +{ + if (cycle_wrapped) + if(self.cnt) + { + self.cnt-=1; + particle2(self.origin+'0 0 17','0 0 25','0 0 25',168,7,5); + } + else + remove(self); +} + +void mflame2_runup (void) [++ 17 .. 33 ] +{ + if (cycle_wrapped) + if(self.cnt) + { + self.cnt-=1; + particle2(self.origin+'0 0 17','0 0 25','0 0 25',168,7,5); + } + else + remove(self); +} + +void mflame3_runup (void) [++ 34 .. 50 ] +{ + if (cycle_wrapped) + if(self.cnt) + { + self.cnt-=1; + particle2(self.origin+'0 0 17','0 0 25','0 0 25',168,7,5); + } + else + remove(self); +} + +void mflame_burn(void) +{ + float damg; + + if ((other.health) && (other != self.owner) && (self.pain_finished time) + return; + + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/pain2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/pain.wav", 1, ATTN_NORM); + + hold_parts = self.parts_gone; + + if (self.health < 30) + { + if (self.parts_gone <= MUMMY_NONE) + mummy_throw_leftarm(); + + if (self.parts_gone <= MUMMY_LARM) + mummy_throw_rightarm(); + + if (self.parts_gone <= MUMMY_RARM) + mummy_throw_rightleg(); + } + else if (self.health < 60) + { + if (self.parts_gone <= MUMMY_NONE) + mummy_throw_leftarm(); + + if (self.parts_gone <= MUMMY_LARM) + mummy_throw_rightarm(); + + } + else if (self.health < 100) + { + if (self.parts_gone == MUMMY_NONE) + mummy_throw_leftarm(); + } + + if (hold_parts != self.parts_gone) + sound (self, CHAN_BODY, "mummy/limbloss.wav", 1, ATTN_NORM); + + +} + + +void lordmummymissile (void) +{ + float result; + vector delta; + + thinktime self : HX_FRAME_TIME; + self.think = lordmummymissile; + + delta = self.enemy.origin - self.origin; + if (vlen(delta) < 70) // Too close to shoot with a missile + mummymelee(); + + if (self.parts_gone == MUMMY_NONE) + { + result = AdvanceFrame($mstafA1,$mstafA24); + + if (self.frame == $mstafA10) + sound (self, CHAN_WEAPON, "mummy/tap.wav", 1, ATTN_NORM); + + if (self.frame == $mstafA17) + launch_mumshot(); + + if (result == AF_END) + mummyrun(); + else + ai_face(); + } + else if (self.parts_gone == MUMMY_LARM) + { + result=AdvanceFrame($mwalkB1,$mwalkB16); // Because there is no one + if (self.frame == $mwalkB16) + launch_mumshot(); + + if (result == AF_END) + mummyrun(); + else + ai_face(); + } + else + mummyrun(); + +} + +void mummymissile (void) +{ + float result,chance; + vector delta; + + thinktime self : HX_FRAME_TIME; + self.think = mummymissile; + + delta = self.enemy.origin - self.origin; + if (vlen(delta) < 70) // Too close to shoot with a missile + mummymelee(); + + if (self.parts_gone == MUMMY_NONE) + { + result = AdvanceFrame($shoota1,$shoota16); + + if (self.frame == $shoota6) + { + makevectors(self.angles); + Create_Missile(self,self.origin + v_forward*14 - v_right * 9 + v_up * 25, + self.enemy.origin+self.enemy.view_ofs,"models/akarrow.mdl","green_arrow",0,1000,mummissile_touch); + } + + if (self.frame == $shoota12) + { + if (enemy_range < RANGE_NEAR) + chance = 0.80; + else if (enemy_range < RANGE_MID) + chance = 0.70; + else if (enemy_range < RANGE_FAR) + chance = 0.40; + + if (random() < chance) // Repeat as necessary + self.frame = $shoota5; + } + + if (result == AF_END) + { + mummyrun(); + } + else + ai_face(); + } + else if (self.parts_gone == MUMMY_LARM) + { + result=AdvanceFrame($shootb1,$shootb16); // Because there is no one + + if (self.frame == $shootb6) + { + makevectors(self.angles); + Create_Missile(self,self.origin + v_forward*14 + v_right * 11 + v_up * 40, + self.enemy.origin+self.enemy.view_ofs,"models/akarrow.mdl","green_arrow",0,1000,mummissile_touch); + } + + if (self.frame == $shootb12) + { + if (enemy_range < RANGE_NEAR) + chance = 0.80; + else if (enemy_range < RANGE_MID) + chance = 0.70; + else if (enemy_range < RANGE_FAR) + chance = 0.40; + + if (random() < chance) // Repeat as necessary + self.frame = $shootb5; + } + + if (result == AF_END) + mummyrun(); + else + ai_face(); + } + else + mummyrun(); + +} + +void mummylordchoice (void) +{ + float chance; + + // He's more likely to use his flame attack when enemy is + // farther away + + if (enemy_range < RANGE_NEAR) + chance = 0.60; + else if (enemy_range < RANGE_MID) + chance = 0.80; + else if (enemy_range < RANGE_FAR) + chance = 0.90; + + if (random() < chance) + lordmummymissile(); + else + mummymissile(); + +} + +void mummypunch () +{ + local vector delta; + local float ldmg; + + delta = self.enemy.origin - self.origin; + if (vlen(delta) > 50) + return; + + self.last_attack=time; + + if (self.classname == "monster_mummy") + ldmg = DMG_MUMMY_PUNCH; + else + ldmg = DMG_MUMMY_PUNCH * 2; + + T_Damage (self.enemy, self, self, ldmg); + + sound (self, CHAN_WEAPON, "weapons/gauntht1.wav", 1, ATTN_NORM); + +} + +void mummybite(void) +{ + local vector delta; + local float ldmg; + + delta = self.enemy.origin - self.origin; + if (vlen(delta) > 50) + return; + + self.last_attack=time; + ldmg = random() * DMG_MUMMY_PUNCH; + + T_Damage (self.enemy, self, self, ldmg); + + sound (self, CHAN_WEAPON, "mummy/bite.wav", 1, ATTN_NORM); +} + +void mummymelee(void) +{ + float result; + vector delta; + + self.nextthink = time + HX_FRAME_TIME; + self.think = mummymelee; + + if (self.parts_gone == MUMMY_NONE) + { + result=AdvanceFrame($mswngA1,$mswngA18); + + if (self.frame == $mswngA8) + sound (self, CHAN_WEAPON, "weapons/vorpswng.wav", 1, ATTN_NORM); + + if (self.frame == $mswngA11) + mummypunch(); + } + else if (self.parts_gone == MUMMY_LARM) + { + result=AdvanceFrame($mswngB1,$mswngB18); + + if (self.frame == $mswngB8) + sound (self, CHAN_WEAPON, "weapons/vorpswng.wav", 1, ATTN_NORM); + + if (self.frame == $mswngB11) + mummypunch(); + } + else if (self.parts_gone == MUMMY_RARM) + { + result=AdvanceFrame($mswingC1,$mswingC10); + + if (self.frame == $mswingC5) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + + if (self.frame == $mswingC8) + mummypunch(); + } + else // He's on the floor so he'll bite your legs off + { +//self.nextthink = time + HX_FRAME_TIME * 2; + thinktime self : HX_FRAME_TIME *2; + + self.mummy_state=MUMMY_DOWN; + result=AdvanceFrame($crawl1,$crawl14); + if (self.frame == $crawl14) + sound (self, CHAN_BODY, "mummy/crawl.wav", 1, ATTN_NORM); + + if (self.frame == $crawl7) + mummybite(); + } + + if (result == AF_END) + { + delta = self.enemy.origin - self.origin; + if (vlen(delta) > 80) + mummyrun(); + } + else + ai_charge(1); +} + +void mummyrun(void) +{ + float distance; + +// self.nextthink = time + HX_FRAME_TIME; + thinktime self : HX_FRAME_TIME; + self.think = mummyrun; + + if (self.parts_gone==MUMMY_NONE) + { + if ((random() < .10) && (self.frame == $mwalkA1)) + { + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/moan2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/moan.wav", 1, ATTN_NORM); + } + + AdvanceFrame($mwalkA1,$mwalkA14); + + if (self.frame==$mwalkA6) + sound (self, CHAN_BODY, "mummy/step.wav", 1, ATTN_NORM); + else if (self.frame==$mwalkA7) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + + + if ((self.frame >= $mwalkA1) && (self.frame <= $mwalkA4)) + distance = 3.25; + else + distance = 2.25; + + } + else if (self.parts_gone==MUMMY_LARM) + { + if ((random() < .10) && (self.frame == $mwalkB1)) + { + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/moan2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/moan.wav", 1, ATTN_NORM); + } + + AdvanceFrame($mwalkB1,$mwalkB16); + if (self.frame==$mwalkB6) + sound (self, CHAN_BODY, "mummy/step.wav", 1, ATTN_NORM); + else if (self.frame==$mwalkB8) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + distance = 3; + } + else if (self.parts_gone==MUMMY_RARM) + { + if ((random() < .10) && (self.frame == $mwalkC1)) + { + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/moan2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/moan.wav", 1, ATTN_NORM); + } + + AdvanceFrame($mwalkC1,$mwalkC18); + if (self.frame==$mwalkC8) + sound (self, CHAN_BODY, "mummy/step.wav", 1, ATTN_NORM); + else if (self.frame==$mwalkC10) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + distance = 3; + + } + else if (self.parts_gone <= MUMMY_LEG) + { + if (self.mummy_state==MUMMY_WAVER) + { + AdvanceFrame($mdeath1,$mdeath13); + if (self.frame==$mdeath13) + self.mummy_state=MUMMY_DOWN; + distance = 0; + } + else + { +// self.nextthink = time + HX_FRAME_TIME * 2; + thinktime self : HX_FRAME_TIME *2; + + AdvanceFrame($crawl1,$crawl14); + + if (self.frame == $crawl2) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + + if ((self.frame >= $crawl1) && (self.frame <= $crawl5)) + distance = 3; + else + distance = 0; + } + } + + ai_run(distance); + +} + + +void mummywalk(void) +{ + float distance; + +// self.nextthink = time + HX_FRAME_TIME + .02; + thinktime self : HX_FRAME_TIME + .02; + self.think = mummywalk; + + if (self.parts_gone==MUMMY_NONE) + { + if ((random() < .10) && (self.frame == $mwalkA1)) + { + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/moan2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/moan.wav", 1, ATTN_NORM); + } + + AdvanceFrame($mwalkA1,$mwalkA14); + + if (self.frame==$mwalkA6) + sound (self, CHAN_BODY, "mummy/step.wav", 1, ATTN_NORM); + else if (self.frame==$mwalkA7) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + + if ((self.frame >= $mwalkA1) && (self.frame <= $mwalkA4)) + distance = 3.25; + else + distance = 2.25; + } + else if (self.parts_gone==MUMMY_LARM) + { + if ((random() < .10) && (self.frame == $mwalkB1)) + { + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/moan2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/moan.wav", 1, ATTN_NORM); + } + + AdvanceFrame($mwalkB1,$mwalkB16); + distance = 2.25; + + if (self.frame==$mwalkB6) + sound (self, CHAN_BODY, "mummy/step.wav", 1, ATTN_NORM); + else if (self.frame==$mwalkB8) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + } + else if (self.parts_gone==MUMMY_RARM) + { + if ((random() < .10) && (self.frame == $mwalkC1)) + { + if (self.classname == "monster_mummy_lord") + sound (self, CHAN_VOICE, "mummy/moan2.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "mummy/moan.wav", 1, ATTN_NORM); + } + + AdvanceFrame($mwalkC1,$mwalkC18); + distance = 2.25; + + if (self.frame==$mwalkC8) + sound (self, CHAN_BODY, "mummy/step.wav", 1, ATTN_NORM); + else if (self.frame==$mwalkC10) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + } + else if (self.parts_gone <= MUMMY_LEG) + { + if (self.mummy_state==MUMMY_WAVER) + { + AdvanceFrame($mdeath1,$mdeath13); + if (self.frame==$mdeath13) + self.mummy_state=MUMMY_DOWN; + distance = 0; + } + else + { +// self.nextthink = time + HX_FRAME_TIME * 2; + thinktime self : HX_FRAME_TIME *2; + + if (self.frame == $crawl2) + sound (self, CHAN_BODY, "mummy/slide.wav", 1, ATTN_NORM); + + AdvanceFrame($crawl1,$crawl14); + if (self.frame == $crawl14) + sound (self, CHAN_BODY, "mummy/crawl.wav", 1, ATTN_NORM); + distance = 2; + } + } + + ai_walk(distance); + +} + +void mummystand(void) +{ +// self.nextthink = time + HX_FRAME_TIME; + thinktime self : HX_FRAME_TIME; + self.think = mummystand; + + self.frame = $mwalkA1; + + if (random() < .5) + ai_stand(); + +} + +/*QUAKED monster_mummy (1 0.3 0) (-16 -16 0) (16 16 50) AMBUSH +No, it's not Keith Richards or Bob Dylan. +It's the mummy. +-------------------------FIELDS------------------------- +health : 150 +experience : 500 +-------------------------------------------------------- +*/ +void monster_mummy (void) +{ + if(deathmatch) + { + remove(self); + return; + } + + if(!self.flags2&FL_SUMMONED) + { + precache_model2("models/mummy.mdl"); + precache_model2 ("models/larm.mdl"); + precache_model2 ("models/leg.mdl"); + precache_model2 ("models/mumshot.mdl"); + precache_model2 ("models/muhead.mdl"); + + precache_sound2 ("mummy/sight.wav"); + precache_sound2 ("mummy/die.wav"); + precache_sound2 ("mummy/mislfire.wav"); + precache_sound2 ("mummy/limbloss.wav"); + precache_sound2 ("mummy/moan.wav"); + precache_sound2 ("mummy/pain.wav"); + precache_sound2 ("mummy/crawl.wav"); + precache_sound2 ("mummy/slide.wav"); + precache_sound2 ("mummy/step.wav"); + precache_sound2 ("mummy/tap.wav"); + precache_sound2 ("mummy/bite.wav"); + + } + + CreateEntityNew(self,ENT_MUMMY,"models/mummy.mdl",mummy_die); + + self.mintel = 3; + self.monsterclass = CLASS_GRUNT; + self.th_stand = mummystand; + self.th_walk = mummywalk; + self.th_run = mummyrun; + self.th_melee = mummymelee; + self.th_missile = mummymissile; + self.th_pain = mummy_pain; + self.parts_gone = MUMMY_NONE; + self.skin = 0; + + self.flags = self.flags|FL_MONSTER; + self.yaw_speed = 10; + self.health = 200; + self.experience_value = 200; + walkmonster_start(); +} + +/*QUAKED monster_mummy_lord (1 0.3 0) (-16 -16 0) (16 16 50) AMBUSH STUCK JUMP PLAY_DEAD DORMANT +He's big, he's bad, he's wrapped in moldy bandages - he's the mummy. +-------------------------FIELDS------------------------- +health : 500 +experience : 300 +-------------------------------------------------------- +*/ +void monster_mummy_lord (void) +{ + if(deathmatch) + { + remove(self); + return; + } + + if(!self.flags2&FL_SUMMONED) + { + precache_model2("models/mummy.mdl"); + precache_model2("models/larm.mdl"); + precache_model2("models/leg.mdl"); + precache_model2("models/mumshot.mdl"); + precache_model2("models/muhead.mdl"); + + precache_sound2 ("mummy/sight2.wav"); + precache_sound2 ("mummy/die2.wav"); + precache_sound2 ("mummy/mislfire.wav"); + precache_sound2 ("mummy/limbloss.wav"); + precache_sound2 ("mummy/moan2.wav"); + precache_sound2 ("mummy/pain2.wav"); + precache_sound2 ("mummy/crawl.wav"); + precache_sound2 ("mummy/slide.wav"); + precache_sound2 ("mummy/step.wav"); + precache_sound2 ("mummy/tap.wav"); + precache_sound2 ("mummy/bite.wav"); + + } + + CreateEntityNew(self,ENT_MUMMY,"models/mummy.mdl",mummy_die); + + self.mintel = 3; + self.monsterclass = CLASS_GRUNT; + self.th_stand = mummystand; + self.th_walk = mummywalk; + self.th_run = mummyrun; + self.th_melee = mummymelee; + self.th_missile = mummylordchoice; + self.th_pain = mummy_pain; + self.parts_gone = MUMMY_NONE; + self.skin = 1; + self.headmodel="models/muhead.mdl"; + + self.flags = self.flags|FL_MONSTER; + self.yaw_speed = 10; + self.health = 400; + self.experience_value = 300; + walkmonster_start(); +} + diff --git a/necro.hc b/necro.hc new file mode 100644 index 0000000..f95fc97 --- /dev/null +++ b/necro.hc @@ -0,0 +1,378 @@ +/* + * $Header: /HexenWorld/Siege/necro.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\players\necroman\final\necro.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\players\necroman\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame cwalk1 cwalk2 cwalk3 cwalk4 cwalk5 +$frame cwalk6 cwalk7 cwalk8 cwalk9 cwalk10 +$frame cwalk11 cwalk12 cwalk13 cwalk14 cwalk15 +$frame cwalk16 cwalk17 cwalk18 cwalk19 cwalk20 + +// +$frame die1 die2 die3 die4 die5 +$frame die6 die7 die8 die9 die10 +$frame die11 die12 die13 die14 die15 +$frame die16 die17 die18 die19 die20 + +// +$frame behead1 behead2 behead3 behead4 behead5 +$frame behead6 behead7 behead8 behead9 behead10 +$frame behead11 behead12 behead13 behead14 behead15 +$frame behead16 behead17 behead18 behead19 behead20 + +// +$frame Hatak1 Hatak2 Hatak3 Hatak4 Hatak5 +$frame Hatak6 Hatak7 Hatak8 + +// +$frame Hfly1 Hfly2 Hfly3 Hfly4 Hfly5 +$frame Hfly6 Hfly7 Hfly8 Hfly9 Hfly10 +$frame Hfly11 Hfly12 Hfly13 Hfly14 + +// +$frame Hpain1 Hpain2 Hpain3 Hpain4 Hpain5 +$frame Hpain6 Hpain7 Hpain8 + +// +$frame Hrun1 Hrun2 Hrun3 Hrun4 Hrun5 +$frame Hrun6 Hrun7 Hrun8 Hrun9 Hrun10 +$frame Hrun11 Hrun12 + +// +$frame Hwait1 Hwait2 Hwait3 Hwait4 Hwait5 +$frame Hwait6 Hwait7 Hwait8 Hwait9 Hwait10 +$frame Hwait11 Hwait12 + +// +$frame Siatak1 Siatak2 Siatak3 Siatak4 Siatak5 +$frame Siatak6 Siatak7 Siatak8 Siatak9 Siatak10 +$frame Siatak11 Siatak12 + +// +$frame Sifly1 Sifly2 Sifly3 Sifly4 Sifly5 +$frame Sifly6 Sifly7 Sifly8 Sifly9 Sifly10 +$frame Sifly11 Sifly12 Sifly13 Sifly14 + +// +$frame Sipain1 Sipain2 Sipain3 Sipain4 Sipain5 +$frame Sipain6 Sipain7 Sipain8 + +// +$frame Sirun1 Sirun2 Sirun3 Sirun4 Sirun5 +$frame Sirun6 Sirun7 Sirun8 Sirun9 Sirun10 +$frame Sirun11 Sirun12 + +// +$frame Siwait1 Siwait2 Siwait3 Siwait4 Siwait5 +$frame Siwait6 Siwait7 Siwait8 Siwait9 Siwait10 +$frame Siwait11 Siwait12 + +// +$frame Statak1 Statak2 Statak3 Statak4 Statak5 +$frame Statak6 Statak7 Statak8 + +// +$frame Stfly1 Stfly2 Stfly3 Stfly4 Stfly5 +$frame Stfly6 Stfly7 Stfly8 Stfly9 Stfly10 +$frame Stfly11 Stfly12 Stfly13 Stfly14 + +// +$frame Stpain1 Stpain2 Stpain3 Stpain4 Stpain5 +$frame Stpain6 Stpain7 Stpain8 + +// +$frame Strun1 Strun2 Strun3 Strun4 Strun5 +$frame Strun6 Strun7 Strun8 Strun9 Strun10 +$frame Strun11 Strun12 + +// +$frame Stwait1 Stwait2 Stwait3 Stwait4 Stwait5 +$frame Stwait6 Stwait7 Stwait8 Stwait9 Stwait10 +$frame Stwait11 Stwait12 + + +/*-------------------------- +ACTUAL (UNIQUE TO CLASS) PLAYER CODE +----------------------------*/ +void() player_necromancer_run; +void() player_necromancer_crouch_stand; +void() player_necromancer_crouch_move; +void() player_necromancer_stand; + +void() player_necromancer_swim = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel<3) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_necromancer_sickle_swim =[++$Sifly1..$Sifly14] +{ + player_necromancer_swim(); +}; + +void() player_necromancer_setstaff_swim =[++$Stfly1..$Stfly14] +{ + player_necromancer_swim(); +}; + +void() player_necromancer_spell_swim =[++$Hfly1..$Hfly14] +{ + player_necromancer_swim(); +}; + +void() player_necromancer_fly = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype!=MOVETYPE_FLY) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_necromancer_sickle_fly =[++$Sifly1..$Sifly14] +{ + player_necromancer_fly(); +}; + +void() player_necromancer_setstaff_fly =[++$Stfly1..$Stfly14] +{ + player_necromancer_fly(); +}; + +void() player_necromancer_spell_fly =[++$Hfly1..$Hfly14] +{ + player_necromancer_fly(); +}; + +void() player_necromancer_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_necromancer_crouch_stand; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (self.velocity_x || self.velocity_y) + self.think=self.th_run; +}; + +void() player_necromancer_sickle_stand =[++$Siwait1..$Siwait12] +{ + player_necromancer_stand(); +}; + +void() player_necromancer_setstaff_stand =[++$Stwait1..$Stwait12] +{ + player_necromancer_stand(); +}; + +void() player_necromancer_spell_stand =[++$Hwait1..$Hwait12] +{ + player_necromancer_stand(); +}; + +void() player_necromancer_run = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_necromancer_crouch_move; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; +}; + +void() player_necromancer_sickle_run =[++$Sirun1..$Sirun12] +{ + player_necromancer_run(); +}; + +void() player_necromancer_setstaff_run =[++$Strun1..$Strun12] +{ + player_necromancer_run(); +}; + +void() player_necromancer_spell_run =[++$Hrun1..$Hrun12] +{ + player_necromancer_run(); +}; + +void() player_necromancer_crouch_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.frame>$cwalk20 || self.frame<$cwalk1) + self.frame=$cwalk1; + if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_stand; + else if (self.velocity_x || self.velocity_y) + self.think=player_necromancer_crouch_move; + thinktime self : HX_FRAME_TIME; +}; + +void() player_necromancer_crouch_move =[++$cwalk1..$cwalk20] +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.movetype==MOVETYPE_FLY) + self.think=player_necromancer_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_run; + else if (!self.velocity_x && !self.velocity_y) + self.think=player_necromancer_crouch_stand; +}; + +void() player_necromancer_attack= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped&&!self.button0) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_necromancer_sickle_attack=[++$Siatak1..$Siatak12] +{ + player_necromancer_attack(); +}; + +void() player_necromancer_spell_attack=[++$Hatak1..$Hatak8] +{ + player_necromancer_attack(); +}; + +void() player_necromancer_setstaff_attack=[++$Statak1..$Statak8] +{ + player_necromancer_attack(); +}; + +void() player_necromancer_pain= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_necromancer_sickle_pain =[++$Sipain1..$Sipain8] +{ + if(self.frame==$Sipain1) + PainSound(); + player_necromancer_pain(); +}; + +void() player_necromancer_setstaff_pain =[++$Stpain1..$Stpain8] +{ + if(self.frame==$Stpain1) + PainSound(); + player_necromancer_pain(); +}; + +void() player_necromancer_spell_pain =[++$Hpain1..$Hpain8] +{ + if(self.frame==$Hpain1) + PainSound(); + player_necromancer_pain(); +}; + +void() player_necromancer_die1=[++$die1..$die10] +{ + if(cycle_wrapped) + { + self.frame=$die20; + self.think=PlayerDead; + } +}; + +void() player_necromancer_die2=[++$die1..$die10] +{ + if(cycle_wrapped) + { + self.frame=$die20; + self.think=PlayerDead; + } +}; + +void() player_necromancer_behead = +{ + self.level=$behead1; + self.dmg=$behead20; + self.cnt=0; + player_behead(); +}; + +void Nec_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1) + { + self.th_stand=player_necromancer_sickle_stand; + self.th_missile=sickle_decide_attack; + self.th_run=player_necromancer_sickle_run; + self.th_pain=player_necromancer_sickle_pain; + self.th_swim=player_necromancer_sickle_swim; + self.th_fly=player_necromancer_sickle_fly; + } + else if(self.weapon==IT_WEAPON4) + { + self.th_stand=player_necromancer_setstaff_stand; + self.th_missile=setstaff_decide_attack; + self.th_run=player_necromancer_setstaff_run; + self.th_pain=player_necromancer_setstaff_pain; + self.th_swim=player_necromancer_setstaff_swim; + self.th_fly=player_necromancer_setstaff_fly; + } + else + { + self.th_stand=player_necromancer_spell_stand; + if(self.weapon==IT_WEAPON2) + self.th_missile=Nec_Mis_Attack; + else + self.th_missile=Nec_Bon_Attack; + self.th_run=player_necromancer_spell_run; + self.th_pain=player_necromancer_spell_pain; + self.th_swim=player_necromancer_spell_swim; + self.th_fly=player_necromancer_spell_fly; + } + if(self.hull!=HULL_CROUCH) + self.think=self.th_stand; +} diff --git a/necspell.hc b/necspell.hc new file mode 100644 index 0000000..d7fceb0 --- /dev/null +++ b/necspell.hc @@ -0,0 +1,15 @@ +void()player_necromancer_spell_attack; +void Nec_Spl_Fire (void) +{ + self.think=player_necromancer_spell_attack; +} + +void spell_idle (void) +{ + self.th_weapon=spell_idle; +} + +void spell_select (void) +{ + spell_idle(); +} diff --git a/newai.hc b/newai.hc new file mode 100644 index 0000000..820139c --- /dev/null +++ b/newai.hc @@ -0,0 +1,848 @@ +/* + * $Header: /HexenWorld/Siege/newai.hc 3 5/25/98 1:39p Mgummelt $ + */ + +void AI_Decision_Dead() +{ + if (self.health>-80) + { // Newly dead + if ((self.ai_state != AI_DEAD) && (self.ai_state != AI_DEAD_TWITCH)) + { + self.ai_new_state = AI_DEAD; + } + else // He's dead Jim + { + if (self.ai_poss_states & AI_DEAD_TWITCH ) + { + self.ai_new_state = AI_DEAD_TWITCH; + self.ai_state = AI_DECIDE; // So states will change + } + else + self.ai_new_state = AI_DEAD; + } + + self.ai_duration = time + 15; // Wait 15 more seconds before vanishing + } + else + self.ai_new_state = AI_DEAD_GIB; + +} + + + +/* +============= +AI_face_enemy + +Turn in place until within an angle to launch an attack +============= +*/ +float AI_face_enemy () +{ + + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + + ChangeYaw (); + + if (FacingIdeal()) // Ready to go get em + return TRUE; + + return FALSE; +} + +/* +============= +AI_infront + +returns 1 if the entity is in front (in sight) of self +============= +*/ +float AI_infront (entity targ) +{ + local vector vec; + local float dot; + + makevectors (self.angles); + vec = normalize (targ.origin - self.origin); + dot = vec * v_forward; + + if ( dot > 0.3) + return TRUE; + + return FALSE; +} + +/* +============= +AI_visionblocked + +returns 1 if the entity is visible to self +============= +*/ +float AI_visionblocked (entity targ) +{ + local vector spot1, spot2; + + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + traceline (spot1, spot2, TRUE, self); // see through other monsters + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (trace_fraction == 1) + return TRUE; + + return FALSE; +} + +/* +============= +AI_calc_range + +returns the range catagorization of an entity reletive to self +0 melee range, will become hostile even if back is turned +1 visibility and infront, or visibility and show hostile +2 infront and show hostile +3 only triggered by damage +============= +*/ +float AI_calc_range (entity targ) +{ + local vector spot1, spot2; + local float rnge; + + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + rnge = vlen (spot1 - spot2); + + if (rnge < 50) + return RANGE_MELEE; + + if (rnge < 400) // Was 250 + return RANGE_NEAR; + + if (rnge < 1000) // Was 800 + return RANGE_MID; + + return RANGE_FAR; +} + +/* +=========== +AI_TargetSearch + +Self is currently not attacking anything, so try to find a target + +Returns TRUE if an enemy was sighted + +When a player fires a missile, the point of impact becomes a fakeplayer so +that monsters that see the impact will respond as if they had seen the +player. + +To avoid spending too much time, only a single client (or fakeclient) is +checked each frame. This means multi player games will have slightly +slower noticing monsters. +============ +*/ +entity AI_TargetSearch () +{ + local entity client; + local float r; + + +// FIXME: need to get sight_entity stuff working + +// spawnflags & 3 is a big hack, because zombie crucified used the first +// spawn flag prior to the ambush flag, and I forgot about it, so the second +// spawn flag works as well +/* if (sight_entity_time >= time - 0.1 && !(self.spawnflags & 3) ) + { + client = sight_entity; + if (client.enemy == self.enemy) + { + return; + } + } + else + {*/ + client = checkclient (); + if (!client) + { + return FALSE; // current check entity isn't in PVS + } +// } + + if (client.classname != "player") + return FALSE; + + if (client.flags & FL_NOTARGET) + return FALSE; + + if (client.items & IT_INVISIBILITY) + return FALSE; + + return client; +} + +/* +=========== +AI_Target + +Some preliminary target decisions +- if just hurt go after the attacker +- if enemy is the world look to see if you can find someone else +============ +*/entity AI_Target () +{ + entity targ; + + // Monster was just hurt - go after the attacker + if (self.just_hurt) + targ = self.enemy; // Set in T-Damage + + else if (self.enemy==world) // No enemies currently + targ=AI_TargetSearch (); // Look for a player to kill + + else // Go after the current enemy + targ = self.enemy; + + return targ; +} + +void AI_MeleeAttack () +{ + AI_face_enemy(); // Turn to face the enemy +} + + +void AI_MissileAttack () +{ + AI_face_enemy(); // Turn to face the enemy +} + + +void AI_Stand () +{ + +} + +void AI_Pain () +{ + AI_face_enemy(); // Turn to face the enemy +} + +void AI_Walk () +{ + movetogoal (self.move_distance); +} + +void AI_Wander () +{ + movetogoal (self.move_distance); +} + + +/* +=========== +AI_Charge + +Charge the enemy - unless monster is too close to enemy, then attack + +============ +*/ +void AI_Charge () +{ + float rnge; + + rnge = AI_calc_range (self.enemy); + + if (rnge==RANGE_MELEE) // Too close - attack enemy + self.ai_new_state=AI_DECIDE; + else + movetogoal (self.move_distance); +} + +/* +=========== +AI_Dead_Gib + +Monster is majorly dead so make him explode + +============ +*/ +void AI_Dead_Gib () +{ + chunk_death(); + + remove(self); +} + + +/* +=========== +AI_Dead + +Monster is dead - in a very real and legally binding sense + +============ +*/ +// FIXME: We need to come up with a nice way of getting rid of dead bodies +void AI_Dead () +{ + if (self.ai_duration <= time) + remove(self); +} + + +/* +=========== +AI_TurnLook + +Turn and look for an enemy that is behind monster + +============ +*/ +void AI_TurnLook () +{ + self.angles_y += 4; +} + + +/* +=========== +AI_Change_State + +Set up the variables for the new AI state +This has the final say in the enemy + +============ +*/ +void AI_Change_State(entity targ) +{ + self.ai_state_func(); // Change monster variables to match the new state + + // Set up the info for the new state + if (self.ai_new_state == AI_STAND) + { + self.ai_move_func = AI_Stand; + self.goalentity = self.pathentity; + self.enemy = world; + } + else if (self.ai_new_state == AI_WALK) + { + self.ai_move_func = AI_Walk; + self.goalentity = self.pathentity; + self.enemy = world; + } + else if (self.ai_new_state==AI_CHARGE) + { + self.ai_move_func = AI_Charge; + self.goalentity = targ; + self.enemy = targ; + } + else if (self.ai_new_state==AI_MISSILE_ATTACK) + { + self.ai_move_func = AI_MissileAttack; + self.goalentity = targ; + self.enemy = targ; + self.ai_duration = time + 9999; // This action must run it course before changing + } + else if (self.ai_new_state==AI_MISSILE_REATTACK) + { + self.ai_move_func = AI_MissileAttack; + self.goalentity = targ; + self.enemy = targ; + self.ai_duration = time + 9999; // This action must run it course before changing + } + else if (self.ai_new_state==AI_MELEE_ATTACK) + { + self.ai_move_func = AI_MeleeAttack; + self.goalentity = targ; + self.enemy = targ; + self.ai_duration = time + 9999; // This action must run it course before changing + } + else if ((self.ai_new_state==AI_PAIN) || (self.ai_new_state==AI_PAIN_CLOSE) || (self.ai_new_state==AI_PAIN_FAR)) + { + self.ai_move_func = AI_Pain; + self.goalentity = self.enemy; + self.ai_duration = time + 9999; // This action must run it course before changing + } + else if (self.ai_new_state==AI_DEAD) + { + self.ai_move_func = AI_Dead; +// self.goalentity = world; +// self.enemy = world; + self.ai_duration = time + 15; // Body will lay there for a while before disappearing + } + else if (self.ai_new_state==AI_DEAD_TWITCH) + { + self.ai_move_func = AI_Dead; + self.goalentity = world; + self.enemy = world; + } + else if (self.ai_new_state==AI_DEAD_GIB) + { + self.ai_move_func = AI_Dead_Gib; + self.goalentity = world; + self.enemy = world; + } + else if (self.ai_new_state==AI_TURNLOOK) + { + self.ai_move_func = AI_TurnLook; + self.goalentity = world; + self.enemy = world; + } + else if (self.ai_new_state==AI_WANDER) + { + self.ai_move_func = AI_Wander; + self.goalentity = world; + self.enemy = world; + } + else + { + self.ai_move_func = AI_Walk; + self.goalentity = self.pathentity; + } + + self.ai_state = self.ai_new_state; +} + +/* +=========== +AI_Decision_Melee + +At MELEE distance from the enemy - decide what state to take + +============ +*/ +entity AI_Decision_Melee(float in_sight,float in_front,entity targ) +{ + float chance; + entity newtarg; + + if (self.just_hurt) + { // What types of pain can it have??? + + if (self.ai_poss_states & AI_PAIN_CLOSE ) + self.ai_new_state = AI_PAIN_CLOSE; + else + self.ai_new_state = AI_PAIN; + + self.just_hurt = FALSE; + newtarg = targ; + } + else + { + chance = random(); // 90% chance of a melee attack + // 20% chance of wandering + // if health is below 10 there is an + // 90% chance he will throw a missile (he's almost dead so take him out with a bang) + // 20% chance of wandering + + if (chance < 0.90) + { + if (self.health > 10) + self.ai_new_state = AI_MELEE_ATTACK; + else + self.ai_new_state = AI_MISSILE_ATTACK; + + self.ai_state = AI_DECIDE; // make it so states change + } + else + { + self.ai_new_state = AI_WANDER; + self.angles_y += random() * 40; + self.ai_duration = time + (random() * 2) + 2; + } + newtarg = targ; + } + + return newtarg; +} +/* +=========== +AI_Decision_Near + +At NEAR distance from the enemy - decide what state to take + +============ +*/ +entity AI_Decision_Near(float in_sight,float in_front,entity targ) +{ + float chance; + entity newtarg; + + if (self.just_hurt) + { + if (self.ai_poss_states & AI_PAIN_CLOSE ) + self.ai_new_state = AI_PAIN_CLOSE; + else + self.ai_new_state = AI_PAIN; + self.just_hurt = FALSE; + newtarg = targ; + } + else + { + chance = random(); // 100% chance of a charging + + if (chance <= 1) // Yes I know, I will add other states soon + { + self.ai_new_state = AI_CHARGE; + self.ai_state = AI_DECIDE; // make it so states change + } + else + { + self.ai_new_state = AI_WANDER; + self.angles_y += random() * 40; + self.ai_duration = time + (random() * 2) + 2; + } + newtarg = targ; + } + + return newtarg; +} + +/* +=========== +AI_Decision_Mid + +At MID distance from the enemy - decide what state to take + +============ +*/ +entity AI_Decision_Mid(float in_sight,float in_front,entity targ) +{ + float chance; + entity newtarg; + + // He was just hurt make him go through pain + if (self.just_hurt) + { + if (self.ai_poss_states & AI_PAIN_CLOSE ) + self.ai_new_state = AI_PAIN_CLOSE; + else + self.ai_new_state = AI_PAIN; + self.just_hurt = FALSE; + newtarg = targ; + } + + // No walls are blocking enemy and enemy's right in front of monster + else if ((in_sight) && (in_front)) + { // Can monster throw missiles + if (self.ai_poss_states & AI_MISSILE_ATTACK ) + { + chance = random(); // 70% chance of throwing a missile + // 30% chance of charging + if (chance <= 0.70) + { + // Not missile attacking yet + if ((self.ai_state != AI_MISSILE_ATTACK) && (self.ai_state != AI_MISSILE_REATTACK)) + self.ai_new_state = AI_MISSILE_ATTACK; + else + { + self.ai_new_state = AI_MISSILE_REATTACK; + self.ai_state = AI_DECIDE; // make it so reattacks can repeat + } + } + else + { + self.ai_new_state = AI_CHARGE; + self.ai_duration = time + (random() * 2) + 1; + } + } + else // No missile attack so charge enemy + { + self.ai_new_state = AI_CHARGE; + self.ai_duration = time + (random() * 2) + 1; + } + newtarg = targ; + } + + // Enemy is close but he is not right in front of monster + // so stand and turn for a minute + else if (in_sight) + { + chance = random(); // 80% chance he'll keep walking + // 20% chance he'll turn looking for the player + + if ((chance <= 0.80) || (self.ai_state != AI_WALK)) // Keep walking + { + self.ai_new_state = AI_WALK; + self.ai_duration = time + random() * 4; + } + else // Stop and turn + { + self.ai_new_state = AI_TURNLOOK; + self.ai_duration = time + random() + 1; + } + newtarg = world; + } + // A wall is in the way so continue do what you're doing + else + { + if (self.ai_state == AI_DECIDE) + self.ai_new_state = AI_STAND; + else + { + self.ai_new_state = self.ai_state; + } + newtarg = world; // Cause we haven't seen him yet + } + + return newtarg; +} + +/* +=========== +AI_Decision_Far + +At FAR distance from the enemy - decide what state to take + +============ +*/ +entity AI_Decision_Far(float in_sight,float in_front,entity targ) +{ + float chance; + entity newtarg; + + // He was just hurt make him go through pain + if (self.just_hurt) // Just given pain + { + if (self.ai_poss_states & AI_PAIN_FAR ) + self.ai_new_state = AI_PAIN_FAR; + else + self.ai_new_state = AI_PAIN; + + self.just_hurt = FALSE; + newtarg = targ; + + } + + // He just finished his pain now he should charge + else if ((self.ai_state==AI_PAIN_FAR) || (self.ai_state==AI_PAIN)) + { + chance = random(); // 45% chance he'll charge + // 45% chance he'll fire a missile (if he can) + // 10% chance of wandering to get away + + + if (chance <= 0.10) + { + self.ai_new_state = AI_WANDER; + self.ai_duration = time + (random() * 2) + 2; + } + else if (chance <= 55) + { + if (self.ai_state & AI_MISSILE_ATTACK) + { + self.ai_new_state = AI_MISSILE_ATTACK; + newtarg = targ; + } + else + { + self.ai_new_state = AI_CHARGE; + self.ai_duration = time + (random() * 4) + 4; + newtarg = targ; + } + } + else + { + self.ai_new_state = AI_CHARGE; + self.ai_duration = time + (random() * 4) + 4; + newtarg = targ; + } + } + + // Not in pain and everyone is too far away and monster has a path to walk + else if (self.pathentity) + { + self.ai_new_state = AI_WALK; + self.goalentity=self.pathentity; + newtarg = world; + } + + // Not in pain and everyone is too far away and no path to walk + else + { + self.ai_new_state = AI_STAND; + newtarg = world; + } + + return newtarg; +} + + +/* +=========== +AI_Decision_Tree + +Have monster look for enemys + +Based on range from enemy decide what state to go to + +Place new state in ai_new_state + +============ +*/ +void AI_Decision_Tree(float state_demanded) +{ + float rnge,in_sight,in_front; + local entity targ,finaltarg; + + if ((state_demanded==FALSE) || (self.ai_new_state == AI_DECIDE)) // Monster is not forcing a state + { + if ((self.ai_duration > time) && (self.ai_new_state != AI_DECIDE)) // Shouldn't change states just yet + return; + + if (self.health > 0) // Still alive + { + + if (self.ai_new_state == AI_DECIDE) // Reset time for the DECIDE state + self.ai_duration = time - 1; + + targ=AI_Target(); // Find a target if there is one + + rnge = AI_calc_range (targ); // Get target range + + in_sight=AI_visionblocked (targ); // Is a wall between monster and target? + + in_front=AI_infront(targ); // Is target in front of monster + + + // Decide on a new state for the monster based on range to enemy + if (rnge == RANGE_FAR) + finaltarg=AI_Decision_Far(in_sight,in_front,targ); + + else if (rnge == RANGE_MID) + finaltarg=AI_Decision_Mid(in_sight,in_front,targ); + + else if (rnge == RANGE_NEAR) + finaltarg=AI_Decision_Near(in_sight,in_front,targ); + + else if (rnge == RANGE_MELEE) // He's very very close + finaltarg=AI_Decision_Melee(in_sight,in_front,targ); + } + else + AI_Decision_Dead(); + } + else // Monster is forcing a state + finaltarg=self.enemy; // Keep it's current enemy + + + if (self.ai_new_state!=self.ai_state) // Did we just change states?? + AI_Change_State(finaltarg); + +} + + +/* +=========== +AI_Main + +Main loop for monster AI + + - decide on state of monster + - use monster's own AI function + - use main movement function + +============ +*/ +void AI_Main() +{ + float demand_state; + + if (!comamode) // Freeze monsters + { + self.ai_frame_time=0; + + demand_state=FALSE; + + do + { + AI_Decision_Tree(demand_state); // Should monster change it's current state + + self.ai_self_func(); // AI particular to this type of monster (Archer_Walk Archer_Stand...) + + // Did monster force a change in ai state? Change it before running ai_move_func + if (self.ai_state != self.ai_new_state) + demand_state = TRUE; + else + { + demand_state = FALSE; + + self.ai_move_func(); // General monster AI AI_Walk, AI_Stand ... + + if (self.ai_state != self.ai_new_state) // was a change in AI forced?? + demand_state = TRUE; + else + demand_state = FALSE; + } + + } while (demand_state==TRUE); + } + else + AI_TargetSearch (); + + if (!self.ai_frame_time) + self.nextthink = time + HX_FRAME_TIME; + else + { + self.nextthink = time + self.ai_frame_time; + } +} + +void AI_start () +{ + + self.origin_z += 1; // raise off floor a bit + droptofloor(); + + if (!walkmove(0,0, FALSE)) + { + dprint ("walkmonster in wall at: "); + dprint (vtos(self.origin)); + dprint ("\n"); + } + + if (self.target) + { + self.goalentity = self.pathentity = find(world, targetname, self.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.pathentity) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } + } + + self.think = AI_Main; +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; + + +} + +void AI_Land_Init () +{ + + self.takedamage = DAMAGE_YES; + self.flags2+=FL_ALIVE; + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 20; + self.view_ofs = '0 0 25'; + self.use = monster_use; + self.flags = self.flags | FL_MONSTER; + self.enemy = world; + self.ai_state = AI_DECIDE; + +// delay drop to floor to make sure all doors have been spawned +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; + self.think = AI_start; + total_monsters += 1; +} + diff --git a/newcube.hc b/newcube.hc new file mode 100644 index 0000000..b9df636 --- /dev/null +++ b/newcube.hc @@ -0,0 +1,215 @@ +float cube_distance = 400; + +void spawn_replacement_key (vector spot) +{ +entity newkey; + newkey=spawn(); + newkey.puzzle_id = g_keyname; + newkey.model = g_keymdl; + newkey.flags2 = FL2_REPLACEMENT;//don't spawn another tracker + newkey.spawnflags(+)8; + newkey.classname="puzzle_piece"; + setorigin(newkey,spot); + newkey.think = puzzle_piece; + thinktime newkey : 0; +} + +entity key_tracker_vigil () +{ +entity find_key,found, zombie_keyman; + //first look for a player with it + if(!g_keyname) + g_keyname = "cskey"; + find_key=find(world,puzzle_inv1,g_keyname); + if(find_key!=world) + if(find_key.netname=="") + {//dropped client still has it + dprint("Error! Person with no name has the key!!!\n"); + zombie_keyman = find_key; + find_key=world; + } + + if(find_key==world) + {//No one is carrying it, look for key itself + if(!g_keymdl) + g_keymdl = "models/puzzle/cskey.mdl"; + find_key=find(world,model,g_keymdl); + if(find_key==world) + {//key not on map + if(self.classname!="cube_of_force") + { + if(zombie_keyman!=world) + {//take from zombie, make not solid and spawn new key + dprint("zombie has only key! Spawning replacement at: "); + if(pointcontents(zombie_keyman.origin)!=CONTENT_SOLID) + { + dprintv("%s\n",zombie_keyman.origin); + spawn_replacement_key(zombie_keyman.origin); + } + else + { + dprintv("%s\n",self.origin); + spawn_replacement_key(self.origin); + } + WriteByte(MSG_ALL,SVC_NONEHASKEY); + zombie_keyman.puzzle_inv1=""; + zombie_keyman.solid=SOLID_NOT; + // zombie_keyman.flags(-)FL_CLIENT; + // remove(zombie_keyman); + find_key=find(world,model,g_keymdl); + if(!find_key) + dprint("What the FUCK? Just made key and can't find it!\n"); + } + else + {//no one has it and it's not there- wtf?! + dprintv("Key was LOST! Spawning replacement at %s\n",self.origin); + spawn_replacement_key(self.origin); + WriteByte(MSG_ALL,SVC_NONEHASKEY); + } + } + } + else if(pointcontents(find_key.origin)==CONTENT_SOLID) + { + if(self.classname!="cube_of_force") + { + setorigin(find_key,self.origin); + WriteByte(MSG_ALL,SVC_NONEHASKEY); + } + } + else if(self.classname!="cube_of_force")//super hacky!!! + { + found=find(world,netname,"door"); + while(found) + { + if(overlapped(found,find_key)) + { + dprintv("Key inside a door, moving it to %s\n",self.origin); + setorigin(find_key,self.origin); + found=world; + } + else + found=find(found,netname,"door"); + } + } + } + + if(self.classname=="cube_of_force") + return find_key; + else + { + self.think=key_tracker_vigil; + thinktime self : 1;//Check every second + } +} + +void spawn_key_tracker () +{ +entity keytracker; + keytracker=spawn(); + setorigin(keytracker,self.origin); + keytracker.think = key_tracker_vigil; + thinktime keytracker: 1; +} + +void CubeDie(void) +{ + stopSound(self,0); + self.owner.artifact_flags(-)self.artifact_flags; + remove(self); +} + +//Key Finder +void cube_point_to_key () +{//fixme - doesn't always work +entity find_key; +vector org,key_spot; + if(self.lifetimestartframe&&(self.weaponframe>endframe||self.weaponframestartframe)) ) + { + self.weaponframe=startframe; + return WF_CYCLE_STARTED; + } + else if(self.weaponframe==endframe) + { + self.weaponframe=startframe; + return WF_CYCLE_WRAPPED; + } + + if(startframe>endframe) + self.weaponframe=self.weaponframe - 1; + else if(startframe 0. if so, come back alive +//This could happen by magic or by fire for fire imp or cold for ice imp + else if(self.health>0) + { + self.takedamage = DAMAGE_YES; + self.flags (+) FL_FLY; + self.flags2 (+) FL_ALIVE; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_FLY; + if(self.classname=="monster_imp_lord") + { + setsize (self, '-32 -32 0', '32 32 56'); + self.hull=HULL_SCORPION; + } + else + { + setsize (self, '-16 -16 0', '16 16 36'); + self.hull=HULL_CROUCH; + } + self.th_stand (); + return; + } + else + { + self.think=imp_die; + if (self.frame == $death7 || self.frame == $death8 ) // when cycling between these 2 frames during falling, make him flutter more randomly + thinktime self : random(0.05,0.217); + else + thinktime self : HX_FRAME_TIME; + } +} + +void imp_die_init () +{ + setsize (self, '-16 -16 0', '16 16 24'); + self.hull=HULL_CROUCH; + imp_die(); +} + +float check_z_move() +{ +float goaldist,moverange; +entity targ; + if(self.enemy!=world) + targ=self.enemy; + else if(self.goalentity!=world) + targ=self.goalentity; + else + return FALSE; + + if(fabs(targ.origin_z-self.origin_z)<48&&!visible(targ)) + return FALSE; //FIXME: Find an up or down + + if(visible(targ)) + if(!clear_path(targ)) + return FALSE; + + if(targ.origin_z!=self.absmin_z) + { + goaldist=(targ.absmin_z+targ.absmax_z)*0.5-(self.absmax_z+self.absmin_z)*0.5; + moverange=fabs(self.level); + if(goaldist>0&&goaldist>moverange) + goaldist=moverange; + else if(goaldist<0&&goaldist=1) +// self.velocity_z/=2; +// else +// self.velocity_z=0; + + return TRUE; +} + +void imp_ferry () +{ +float dist; +vector org; + walkmove(self.angles_y, self.speed, FALSE); + check_z_move(); + org=self.enemy.origin; + org_z=self.enemy.absmax_z; + dist=vlen(self.origin-org); + if(dist>200) + { + imp_drop(); + return; + } + else// if(self.enemy!=self.movechain) + self.enemy.velocity=normalize(self.origin-org)*dist*5; + self.enemy.angles=self.angles; +} + +void imp_pick_up (void) +{ + self.attack_state=AS_FERRY; + self.goalentity=find(world,targetname,self.target); +} + +void imp_up_down() +{ // Function to make the imp randomly change height +vector end_vec,vec1; + +// dprint("CHECKING UP/DOWN\n"); + if (self.velocity_z > -10.0 && self.velocity_z < 10.0) + { // If we aren't moving up/down that much, maybe we want to change altitudes + self.velocity_z = 0.0; + if (random() < 0.3||self.attack_state==AS_SLIDING) + { // Should we change altitudes? + makevectors (self.angles); + if (random() < 0.5) + { // Go Down + vec1 = self.origin + v_up*-48; + traceline (self.origin,vec1,FALSE,self); + if(trace_fraction==1) + { + end_vec=vec1+v_forward*32; + traceline (vec1,end_vec,FALSE,self); + if (trace_fraction == 1||random()<0.5) + { + //dprint("Goin down\n"); + self.velocity_z = self.speed*-7; + } + } + } + else + { // Go Up + vec1 = self.origin + v_up*88; + traceline (self.origin,vec1,FALSE,self); + if(trace_fraction==1) + { + end_vec=vec1+v_forward*32; + traceline (vec1,end_vec,FALSE,self); + if (trace_fraction == 1||random()<0.5) + { + //dprint("Goin up\n"); + self.velocity_z = self.speed*7; + } + } + } + self.flags(-)FL_ONGROUND; + } + } + else self.velocity_z = self.velocity_z / 1.05; +} + +void imp_set_speeds () +{ +float anglediff,dist; + dist=8; //Movement distance this turn + + anglediff= fabs(self.angles_y - self.ideal_yaw); //How far we're trying to turn + + if (anglediff > 20) // If it is a big distance to turn, then don't move as far forward + dist = dist / 1.5; + + self.level=imp_fly_amounts[self.frame - $impfly1]; + self.speed = dist + self.level*4; //tweaks to speed based on anim frame + + if(!visible(self.enemy)) + self.level*=4; +} + +float imp_check_too_close () +{ +float enemy_zdiff,enemy_hdist; + if(!visible(self.enemy)) + return FALSE; + + enemy_zdiff=fabs(self.origin_z-self.enemy.origin_z); + enemy_hdist=vhlen(self.enemy.origin-self.origin); + if(enemy_zdiff>=77&&enemy_hdist<=77) + { +// dprint("too close!\n"); + return TRUE; + } + return FALSE; +} + +void imp_move () +{ +float too_close; + checkenemy(); + + self.velocity*=1/1.05; + if(imp_check_too_close()) + { + self.ideal_yaw=self.angles_y; + too_close=TRUE; + } + else + ai_face(); + + imp_set_speeds(); + + if(self.attack_state==AS_FERRY) + { + imp_ferry(); + return; + } + + if(self.attack_state==AS_STRAIGHT) + { + if(too_close) + { + if(!walkmove(self.angles_y,self.speed,FALSE)) + movetogoal(self.speed); + } + else + movetogoal(self.speed); + } + else if(self.attack_state==AS_SLIDING) + { //FIXME: make a more intelligent slide? +// dprint("sliding\n"); + enemy_yaw = vectoyaw(self.enemy.origin - self.origin); + movedist=self.speed; + ai_run_slide(); + } + + movestep(0,0,self.level, FALSE); + + if(!check_z_move()) + imp_up_down(); + + if(vlen(self.enemy.origin+self.enemy.proj_ofs-self.origin)<20&&random()<0.2&&self.target!=""&&self.origin_z>self.enemy.absmax_z - 8&&self.spawnflags&PICKUP) + imp_pick_up(); +} + +float imp_new_action () +{ +float too_close; + enemy_vis=visible(self.enemy); + too_close=imp_check_too_close(); + if((random()<0.7&&self.enemy.flags2&FL_ALIVE)||!enemy_vis||too_close) + { + if(self.think!=imp_fly) + { + self.think=imp_fly; + thinktime self : 0; + return TRUE; + } + return FALSE; + } + else + { + if(self.think!=imp_hover) + { + self.think=imp_hover; + thinktime self : 0; + return TRUE; + } + return FALSE; + } + return FALSE; +} + +void imp_strafe_left () [++ $impfly1 .. $impfly20] +{ +vector dir; + ai_face(); + if(cycle_wrapped) + { + self.think=imp_fly; + thinktime self : 0; + return; + } +// else if(self.frame==$impfly1) +// dprint("strafing left\n"); + makevectors(self.angles); + dir='0 0 0' - (v_right*(self.frame - $impfly1)*30); + self.velocity_x=dir_x; + self.velocity_y=dir_y; + check_pos_enemy(); +//FIXME: check for attack? +} + +void imp_strafe_right () [++ $impfly1 .. $impfly20] +{ +vector dir; + ai_face(); + if(cycle_wrapped) + { + self.think=imp_fly; + thinktime self : 0; + return; + } +// else if(self.frame==$impfly1) +// dprint("strafing right\n"); + makevectors(self.angles); + dir=v_right*(self.frame - $impfly1)*30; + self.velocity_x=dir_x; + self.velocity_y=dir_y; + check_pos_enemy(); +//FIXME: check for attack? +} + +void imp_rise () [++ $impfly1 .. $impfly20] +{ + check_pos_enemy(); + if(self.frame==$impfly1) + { +// dprint("shooting up\n"); + self.attack_finished=time+1.7; + self.velocity_z=600; + } + else if(self.frame>$impfly14 &&self.attack_finished 0.1) + { + imp_strafe_left();//Left because you want to go away from it + return TRUE; + } + else if( dot < -0.1) + { + imp_strafe_right(); + return TRUE; + } + dot = proj_spot_dir * v_up; + if ( dot > 0.2) + { + imp_dive(); + return TRUE; + } + else if( dot < 0) + { + imp_rise(); + return TRUE; + } +// dprint("no defense dir found\n"); + return FALSE; + } + return FALSE; +} + +void imp_attack(void) +{ + if (self.origin_z - self.enemy.origin_z < 50 && vhlen(self.origin-self.enemy.origin) < 64) + { + self.v_angle=self.angles; + FireMelee (20,10,64); + } + else if (self.classname == "monster_imp_ice"||(self.classname == "monster_imp_lord"&&random()<0.5)) + { + sound (self, CHAN_WEAPON, "imp/shard.wav", 1, ATTN_NORM); + + makevectors (self.angles); + do_shard('14 8 0',360 + random()*150, '0 0 0'); + do_shard('14 8 0',360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + do_shard('14 8 0',360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + if (random() < 0.5) + do_shard('14 8 0',360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + if (random() < 0.5) + do_shard('14 8 0',360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + if (random() < 0.5) + do_shard('14 8 0',360 + random()*150, (v_forward * ((random() * 40) - 20)) + + (v_right * ((random() * 40) - 20)) + + (v_up * ((random() * 20) - 10))); + } + else + { + sound (self, CHAN_WEAPON, "imp/fireball.wav", 1, ATTN_NORM); + do_fireball('14 8 0'); + } +} + +void imp_attack_anim() [++ $impfir1 .. $impfir21] +{ + check_pos_enemy(); + + ai_face(); + + if(imp_check_defense()) + return; + + if (self.frame == $impfir17) + imp_attack(); + else if (cycle_wrapped) + { + self.think=imp_fly; + if(visible(self.enemy)&&self.enemy.flags2&FL_ALIVE) + if(random()<0.2+skill/10) + self.think=imp_attack_anim; + self.attack_finished=time + 1; + thinktime self : 0; + } +} + +void imp_abort_swoop () [++ $swpout1 .. $swpout15] +{ + check_pos_enemy(); + if(self.velocity_x>10) + self.velocity_x/=2; + else + self.velocity_x=0; + + if(self.velocity_x>10) + self.velocity_y/=2; + else + self.velocity_y=0; + + if(self.frame==$swpout15) + { + self.attack_finished=time + 1; + self.think=imp_fly; + thinktime self : 0; + } +} + +void imp_swoop_end () [++ $swpend1 .. $swpend15] +{ + check_pos_enemy(); + self.flags (-) FL_ONGROUND; + + // swoop him back up and slow down his forward velocity (xy) + self.velocity_z += 15; + self.velocity_x /= 1.2; + self.velocity_y /= 1.2; + + if (self.frame == $swpend15) + { // Finished swooping + self.attack_finished=time + 1; + self.velocity = '0 0 0'; + self.yaw_speed = 8; + self.think=imp_hover; + thinktime self : 0; + } +} + +void imp_swoop_charge () [++ $swpcyc1 .. $swpcyc4] +{ +vector dir,destiny,org; + check_pos_enemy(); + destiny=self.enemy.origin+self.enemy.proj_ofs; + org=(self.absmin+self.absmax)*0.5; + enemy_vis=visible(self.enemy); + enemy_infront=infront(self.enemy); + enemy_range=vlen(destiny - org); + if(self.enemy.last_attack>time - 1 &&fov(self,self.enemy,45)) + { + self.velocity_z+=200; + imp_abort_swoop(); + } + else if(enemy_vis&&enemy_infront&&enemy_range<2000) + { + dir=normalize(destiny-org); + self.velocity=dir*(400+self.count*10); + ai_face(); + + self.count += 1; + + if (self.flags & FL_ONGROUND || self.count > 30) + { // Didn't hit our target, so go back up + self.flags (-) FL_ONGROUND; + imp_abort_swoop(); + } + } + else + imp_abort_swoop(); +} + +void imp_enter_swoop () [++ $swoop1 .. $swoop20] +{ +vector vec; + check_pos_enemy(); + if(self.frame==$swoop1) + { + self.yaw_speed=15; + self.count=140; + self.velocity = '0 0 0'; + + sound (self, CHAN_BODY, "imp/swoop.wav", 1, ATTN_NORM); + } + + ai_face(); + self.count *= 1.15; + + if (self.frame >= $swoop12) + { // Start to swoop down + vec = normalize(self.enemy.origin - self.origin + self.enemy.proj_ofs); + self.velocity = vec*self.count; + if (self.frame <= $swoop13 ) + { // If we haven't pulled out yet, keep going straight down + self.velocity_x = self.velocity_y = 0; + } + if(self.origin_z - self.enemy.absmax_z>50&&self.frame==$swoop13) + self.frame=$swoop12; + } + + if (self.frame == $swoop12 || self.frame == $swoop13 ) + { // Swoop down cycling frames + if (self.flags & FL_ONGROUND) + { // Ran into something on the way down + self.flags (-) FL_ONGROUND; + self.frame = $swoop14; + self.count = 280; + } + if (self.origin_z - self.enemy.origin_z < 60) + { // Have to flatten out soon + self.frame = $swoop14; + self.count = 280; + } + } + + if(self.frame==$swoop20) + { + self.count=0; + self.think=imp_swoop_charge; + thinktime self : 0.05; + } +} + +void imp_straight_swoop () [-- $swpout15 .. $swpout1] +{ + check_pos_enemy(); + ai_face(); + if(imp_check_defense()) + return; + + if(self.frame==$swpout15) + { + self.yaw_speed=15; + self.count=140; + self.velocity = '0 0 0'; + + sound (self, CHAN_BODY, "imp/swoop.wav", 1, ATTN_NORM); + } + + if(self.frame==$swpout1) + { + self.count=0; + self.think=imp_swoop_charge; + thinktime self : 0.05; + } +} + +void() imp_touch = +{ +float damg; +vector punch; + + if((self.frame >= $swpcyc1 && self.frame <= $swpcyc4 )||(self.frame>=$swoop16 &&self.frame<=$swoop20)) + { // If we are in swoop attack frames + self.flags (-) FL_ONGROUND; + sound (self, CHAN_WEAPON, "imp/swoophit.wav", 1, ATTN_NORM); + + self.think=imp_swoop_end; + if (other.takedamage) + { // We sucessfully hit something + + punch=normalize(self.angles)* -1; + punch *= damg; + other.punchangle=punch; + if(self.classname == "monster_imp_lord") + { + damg = (20 + (self.count *3)); + T_Damage (other, self, self.owner, damg); + other.velocity_x += self.velocity_x*2; + other.velocity_y += self.velocity_y*2; + if(other.movetype==MOVETYPE_FLY) + { + if(other.flags&FL_ONGROUND) + other.velocity_z=200; + } + else + other.velocity_z=200; + other.flags(-)FL_ONGROUND; + } + else + { + damg = (10 + (self.count / 2)); + T_Damage (other, self, self.owner, damg); + } + } + else if(vlen(self.velocity)>600) + { + makevectors(self.angles); + SpawnPuff(self.origin+self.proj_ofs+v_forward*self.absmax_x,'0 0 0',10,self); + self.pain_finished=-666; + self.think=self.th_pain; + } + self.velocity=other.velocity;//?? + } +}; + +float imp_check_attack () +{ +float enemy_hdist,enemy_zdiff,swoop_no_drop; +vector destiny,org; + + if(!self.monster_awake||self.enemy==world) + return FALSE; + + enemy_vis=visible(self.enemy); + if (!enemy_vis) + { + if(self.mintel) + SetNextWaypoint(); + self.attack_state = AS_STRAIGHT; + return FALSE; + } + else if(self.mintel) + { + self.goalentity=self.enemy; + self.wallspot=(self.enemy.absmin+self.enemy.absmax)*0.5; + } + + if(self.attack_state==AS_FERRY) + return FALSE; + + if (time < self.attack_finished) + return FALSE; + + enemy_infront=infront(self.enemy); + if(!enemy_infront) + return FALSE; + + enemy_range=range(self.enemy); + if (enemy_range == RANGE_FAR) + { + self.attack_state = AS_STRAIGHT; + return FALSE; + } + +// see if any entities are in the way of the shot + + destiny=self.enemy.origin+self.enemy.proj_ofs; + org=(self.absmin+self.absmax)*0.5; + + self.attack_state = AS_STRAIGHT; + traceline (org, destiny, FALSE, self); + if (trace_ent != self.enemy) + { +// dprint("Imp shot blocked by: "); +// dprint(trace_ent.classname); +// dprint("\n"); + if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + {//Don't have a clear shot, and don't want to shoot obstruction +// dprint("\n"); + self.attack_state = AS_SLIDING; + return FALSE; + } +// dprint("- trying to kill it\n"); + } + + if(random()<0.2+skill/10) + return FALSE; + + if(!self.spawnflags & MONSTER_STAND_GROUND) + { + float swoop_no_drop; + swoop_no_drop=FALSE; + + enemy_hdist=vhlen(destiny-org); + enemy_zdiff=org_z - destiny_z; + if(enemy_zdiff<=36&&random()<0.3) + swoop_no_drop=TRUE; + + if((enemy_hdist>100&&enemy_zdiff>36)||swoop_no_drop) + { + tracearea(org,org-'0 0 1'*enemy_zdiff,'-16 -16 0','16 16 28',FALSE,self); + if(trace_fraction==1||swoop_no_drop) + { + if(swoop_no_drop) + tracearea(org,destiny,'-16 -16 0','16 16 28',FALSE,self); + else + tracearea(org-'0 0 1'*enemy_zdiff,destiny,'-16 -16 0','16 16 28',FALSE,self); + if(trace_ent==self.enemy) + { + if(swoop_no_drop) + self.think=imp_straight_swoop; + else + self.think=imp_enter_swoop; + thinktime self : 0; + return TRUE; + } + } + } + } + + self.think=imp_attack_anim; + thinktime self : 0; + return TRUE; +} + +void imp_hover() [++ $impfly1 .. $impfly20] +{ +float too_close; + checkenemy(); + if(!self.enemy) + if(imp_find_target()) + return; + + self.velocity*=1/1.05; + ai_face(); + imp_set_speeds(); + check_z_move(); + + if(imp_check_defense()) + return; + + if(imp_check_attack()) + return; + + if(self.enemy!=world) + { + too_close=imp_check_too_close(); + enemy_vis=visible(self.enemy); + if(!enemy_vis||too_close||self.attack_state==AS_SLIDING) + { + self.think=imp_fly; + thinktime self : 0; + return; + } + } + + if(self.enemy!=world||self.goalentity!=world) + if(imp_new_action()) + return; +} + +void() stone_imp_awaken = [++ $impup7 .. $impup23] +{ + if(self.frame==$impup10) + { + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.count = 0; + self.monster_awake = TRUE; + setsize (self, '-16 -16 0', '16 16 36'); + self.hull=HULL_CROUCH; + self.mass = 3; + self.health=self.max_health; + self.flags (+) FL_MONSTER | FL_FLY; + self.movetype = MOVETYPE_FLY; + self.takedamage=DAMAGE_YES; + self.touch= imp_touch; + self.th_die = imp_die_init; + self.spawnflags (-) SF_IMP_DORMANT; + + self.artifact_active (-) ARTFLAG_STONED; + sound (self, CHAN_VOICE, "fx/wallbrk.wav", 1, ATTN_NORM); + while(chunk_cnt < CHUNK_MAX) + { + CreateModelChunks(self.size,.7); + chunk_cnt+=1; + } + self.skin=self.oldskin; + if(self.skin) + self.classname="monster_imp_ice"; + else + self.classname="monster_imp_fire"; + + self.thingtype=THINGTYPE_FLESH; + self.scale=1; + } + else if(self.frame==$impup23) + self.think=imp_fly; +}; + +void imp_pain_anim2 () [++ $impup6 .. $impup14] +{ + check_pos_enemy(); + if(self.frame==$impup14) + { + if (self.spawnflags & SF_IMP_DORMANT) + { + self.frame=$impup1; + self.think=stone_imp_awaken; + } + else + self.think=imp_hover; + thinktime self : 0; + } +} + +void imp_pain_anim1 () [-- $impup14 .. $impup6] +{ + check_pos_enemy(); + if(self.frame==$impup6) + { + self.think=imp_pain_anim2; + thinktime self : 0; + } +} + +void(entity attacker, float damage) imp_pain = +{ + if(self.pain_finished>time) + return; + + if(self.targetname!=""&&self.skin==2) + { + self.think=SUB_Null; + self.nextthink=-1; + return; + } + + if(random()<0.5&&self.pain_finished!=-666)//FIXME: make more logical + return; + + self.pain_finished=time+3;//only react to pain once every 3 seconds max + + if(self.attack_state==AS_FERRY&&random()<0.2) + imp_drop(); + +//FIXME: pain sound + self.think=imp_pain_anim1; + thinktime self : 0; +}; + +void imp_use (void) +{ + self.use=SUB_Null; + self.targetname=""; + + if(activator.classname=="player") + self.enemy=self.goalentity=activator; + else + dprint("ERROR: monster not activated by player!\n"); + + self.frame=$impup1; + self.think=stone_imp_awaken; + thinktime self : random(); +} + +float imp_find_target(void) +{ // Imp in waiting state + + if (self.spawnflags & SF_IMP_DORMANT) + return FALSE; + + if (LocateTarget()) + { // We found a target + self.goalentity = self.enemy; + self.think = self.th_run; + thinktime self : 0; + //self.nextthink = time + 6;//why 6? + return TRUE; + } + return FALSE; +} + +void imp_wait() [++ $impwat1 .. $impwat24] +{ + if(imp_find_target()) + return; +} + +void imp_fly () [++ $impfly1 .. $impfly20] +{ + imp_move(); + + if(imp_check_defense()) + return; + + if(imp_check_attack()) + return; + + if(imp_new_action()) + return; +} + +void imp_awaken () [++ $impup1 .. $impup23] +{ + check_pos_enemy(); + movestep(0,0,imp_up_amounts[self.frame - $impup1], FALSE); + walkmove(self.angles_y, imp_up_amounts[self.frame - $impup1] / 2.0, FALSE); + + if (self.frame == $impup23) + { + self.monster_awake = TRUE; + self.think = imp_fly; + thinktime self : 0; + } +} + + +void impmonster_start_go () +{ + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 5.0; + self.view_ofs = '0 0 25'; + if(!self.use) + self.use = monster_use; + + self.pausetime = 99999999; + + if(self.targetname) + { + self.frame=$impwat1; + self.think=imp_use; + self.nextthink=-1; + } + else + self.th_stand (); +} + +void impmonster_start () +{ + thinktime self : random(0.5); + + self.think = impmonster_start_go; + total_monsters = total_monsters + 1; +} + +void init_imp (float which_skin) +{ + if (deathmatch&&self.wait!=-1&&self.classname!="monster_imp_lord") + { + remove(self); + return; + } + + if(!self.flags2&FL_SUMMONED) + { + precache_model2 ("models/imp.mdl"); + precache_model2 ("models/h_imp.mdl");//empty for now + if (self.classname == "monster_imp_lord") + { + precache_model2 ("models/shardice.mdl"); + precache_model ("models/fireball.mdl"); + } + else if (self.classname == "monster_ice_imp"||self.classname == "monster_imp_ice") + precache_model2 ("models/shardice.mdl"); + else + precache_model ("models/fireball.mdl"); + precache_model2 ("models/ring.mdl"); + precache_sound2("imp/up.wav"); + precache_sound2("imp/die.wav"); + precache_sound2("imp/swoophit.wav"); + precache_sound2("imp/swoop.wav"); + precache_sound2("imp/fly.wav"); + precache_sound2("imp/fireball.wav"); + precache_sound2("imp/shard.wav"); + } + + self.solid = SOLID_SLIDEBOX; + setmodel (self, "models/imp.mdl"); + if (self.classname == "monster_imp_lord") + { + self.drawflags(+)SCALE_ORIGIN_BOTTOM; + self.scale=2.5; + setsize (self, '-32 -32 0', '32 32 56'); + self.hull=HULL_SCORPION; + } + else + { + setsize (self, '-16 -16 0', '16 16 36'); + self.hull=HULL_CROUCH; + } + self.headmodel = "models/h_imp.mdl"; + + if(self.wait!=-1) + { + self.movetype = MOVETYPE_FLY; + self.takedamage=DAMAGE_YES; + + self.skin = which_skin; + self.impType = which_skin; + if(which_skin==3) + self.flags (+) FL_COLDHEAL|FL_FIREHEAL; + else if(which_skin==1) + self.flags (+) FL_COLDHEAL; + else + self.flags (+) FL_FIREHEAL; + + self.flags2 (+) FL_ALIVE; + self.thingtype=THINGTYPE_FLESH; + if (self.classname == "monster_imp_lord") + { + self.max_health=self.health = 400; +// self.experience_value = 3000; + self.mass = 10; + } + else + { + self.max_health=self.health = 100; +// self.experience_value = 500; + self.mass = 3; + } + self.mintel = 5; + + if (self.spawnflags & MONSTER_HOVER) + { + self.th_stand = imp_hover; + self.th_walk = imp_fly; + } + else + { + self.th_stand = imp_wait; + self.th_walk = imp_awaken; + } + self.th_run = self.th_walk; + self.th_pain = imp_pain; + self.th_die = imp_die_init; + self.th_missile = imp_enter_swoop; + self.th_melee = imp_attack; + self.touch = imp_touch; + } + + self.yaw_speed=8; + self.speed=10; + self.attack_state = AS_STRAIGHT; + self.level=0; + self.monster_awake = FALSE; + self.view_ofs=self.proj_ofs='0 0 25'; + + if (self.spawnflags & SF_IMP_DORMANT) + { + self.classname="gargoyle"; + self.scale=1.5; + self.artifact_active (+) ARTFLAG_STONED; + setsize (self, '-16 -16 0', '16 16 36'); + self.hull=HULL_CROUCH; + self.takedamage=DAMAGE_NO_GRENADE; + self.thingtype=THINGTYPE_GREYSTONE; + self.movetype=MOVETYPE_PUSHPULL; + self.touch=obj_push; + self.health+=100; + self.mass=100; + self.th_die = chunk_death; + if(self.wait!=-1) + { + self.use = imp_use; + self.oldskin = self.skin; + self.th_stand = imp_wait; + } + self.skin=2; + } + else + self.flags (+) FL_MONSTER | FL_FLY; + + if(self.wait!=-1) + impmonster_start(); + else + self.frame = $impwat1; +} + +/*QUAKED monster_imp_ice (1 0.3 0) (-16 -16 0) (16 16 55) STAND HOVER x x DORMANT +Grunt monster - common. Shoots multiple ice shards. Can only be killed by defrosting it. + +DORMANT = uses the grey stone texture to make it look like a gargoyl- will wake up if the player looks at him long enough, gets close, or hurts him. +-------------------------FIELDS------------------------- +wait = if you give it a -1, the gargoyle will not come alive, it's just a decoration +-------------------------------------------------------- + +*/ +void monster_imp_ice () +{ + init_imp(1); +} + +/*QUAKED monster_imp_fire (1 0.3 0) (-16 -16 0) (16 16 55) STAND HOVER x x DORMANT +Grunt monster - common. Shoots a fireball. Can only be killed by defrosting it. + +DORMANT = uses the grey stone texture to make it look like a gargoyl- will wake up if the player looks at him long enough, gets close, or hurts him. +-------------------------FIELDS------------------------- +wait = if you give it a -1, the gargoyle will not come alive, it's just a decoration +-------------------------------------------------------- + +*/ +void monster_imp_fire () +{ + init_imp(0); +} + +/*QUAKED monster_imp_lord (1 0.3 0) (-16 -16 0) (16 16 55) STAND HOVER x x DORMANT +Grunt monster - common. Shoots multiple ice shards. Can only be killed by defrosting it. + +DORMANT = uses the grey stone texture to make it look like a gargoyl- will wake up if the player looks at him long enough, gets close, or hurts him. +-------------------------FIELDS------------------------- +wait = if you give it a -1, the gargoyle will not come alive, it's just a decoration +-------------------------------------------------------- + +*/ +void monster_imp_lord () +{ + init_imp(3); +} diff --git a/newplay.hc b/newplay.hc new file mode 100644 index 0000000..15fd4c6 --- /dev/null +++ b/newplay.hc @@ -0,0 +1,1174 @@ +/* +============================================================================== + +ALL PLAYERS FRAME CONTROL!!! +MG + +============================================================================== +*/ + +//================================================================= +//PALADIN +// +$frame attgnt1 attgnt2 attgnt3 attgnt4 attgnt5 +$frame attgnt6 attgnt7 attgnt8 attgnt9 attgnt10 +$frame attgnt11 + +// +$frame pattstf1 pattstf2 pattstf3 pattstf4 + +// +$frame attswd1 attswd2 attswd3 attswd4 attswd5 +$frame attswd6 attswd7 attswd8 attswd9 attswd10 +$frame attswd11 attswd12 + +// +$frame pcrouch1 pcrouch2 pcrouch3 pcrouch4 pcrouch5 +$frame pcrouch6 pcrouch7 pcrouch8 pcrouch9 pcrouch10 +$frame pcrouch11 pcrouch12 pcrouch13 pcrouch14 pcrouch15 +$frame pcrouch16 pcrouch17 pcrouch18 pcrouch19 pcrouch20 + +// +$frame pdeath1 pdeath2 pdeath3 pdeath4 pdeath5 +$frame pdeath6 pdeath7 pdeath8 pdeath9 pdeath10 +$frame pdeath11 pdeath12 pdeath13 pdeath14 pdeath15 +$frame pdeath16 pdeath17 pdeath18 pdeath19 pdeath20 + +// +$frame pdecap1 pdecap2 pdecap3 pdecap4 pdecap5 +$frame pdecap6 pdecap7 pdecap8 pdecap9 pdecap10 +$frame pdecap11 pdecap12 pdecap13 pdecap14 pdecap15 +$frame pdecap16 pdecap17 pdecap18 pdecap19 pdecap20 +$frame pdecap21 pdecap22 pdecap23 pdecap24 pdecap25 +$frame pdecap26 pdecap27 pdecap28 + +// +$frame flygnt1 flygnt2 flygnt3 flygnt4 flygnt5 +$frame flygnt6 flygnt7 flygnt8 flygnt9 flygnt10 +$frame flygnt11 flygnt12 flygnt13 flygnt14 flygnt15 + +// +$frame pflystf1 pflystf2 pflystf3 pflystf4 pflystf5 +$frame pflystf6 pflystf7 pflystf8 pflystf9 pflystf10 +$frame pflystf11 pflystf12 pflystf13 pflystf14 pflystf15 + +// +$frame flyswd1 flyswd2 flyswd3 flyswd4 flyswd5 +$frame flyswd6 flyswd7 flyswd8 flyswd9 flyswd10 +$frame flyswd11 flyswd12 flyswd13 flyswd14 flyswd15 + +// +$frame pjump1 pjump2 pjump3 pjump4 pjump5 +$frame pjump6 pjump7 pjump8 pjump9 pjump10 +$frame pjump11 pjump12 + +// +$frame paingnt1 paingnt2 paingnt3 paingnt4 paingnt5 +$frame paingnt6 paingnt7 + +// +$frame ppainstf1 ppainstf2 ppainstf3 ppainstf4 ppainstf5 +$frame ppainstf6 ppainstf7 + +// +$frame painswd1 painswd2 painswd3 painswd4 painswd5 +$frame painswd6 painswd7 + +// +$frame rungnt1 rungnt2 rungnt3 rungnt4 rungnt5 +$frame rungnt6 rungnt7 rungnt8 rungnt9 rungnt10 +$frame rungnt11 rungnt12 + +// +$frame prunstf1 prunstf2 prunstf3 prunstf4 prunstf5 +$frame prunstf6 prunstf7 prunstf8 prunstf9 prunstf10 +$frame prunstf11 prunstf12 + +// +$frame runswd1 runswd2 runswd3 runswd4 runswd5 +$frame runswd6 runswd7 runswd8 runswd9 runswd10 +$frame runswd11 runswd12 + +// +$frame stdgnt1 stdgnt2 stdgnt3 stdgnt4 stdgnt5 +$frame stdgnt6 stdgnt7 stdgnt8 stdgnt9 stdgnt10 +$frame stdgnt11 stdgnt12 stdgnt13 + +// +$frame pstdstf1 pstdstf2 pstdstf3 pstdstf4 pstdstf5 +$frame pstdstf6 pstdstf7 pstdstf8 pstdstf9 pstdstf10 +$frame pstdstf11 pstdstf12 pstdstf13 + +// +$frame stdswd1 stdswd2 stdswd3 stdswd4 stdswd5 +$frame stdswd6 stdswd7 stdswd8 stdswd9 stdswd10 +$frame stdswd11 stdswd12 stdswd13 + + +//================================================================= +$framevalue 0 + +//CRUSADER +// +$frame ccrouch1 ccrouch2 ccrouch3 ccrouch4 ccrouch5 +$frame ccrouch6 ccrouch7 ccrouch8 ccrouch9 ccrouch10 +$frame ccrouch11 ccrouch12 ccrouch13 ccrouch14 ccrouch15 +$frame ccrouch16 ccrouch17 ccrouch18 ccrouch19 ccrouch20 + +// +$frame cdecap1 cdecap2 cdecap3 cdecap4 cdecap5 +$frame cdecap6 cdecap7 cdecap8 cdecap9 cdecap10 +$frame cdecap11 cdecap12 cdecap13 cdecap14 cdecap15 +$frame cdecap16 cdecap17 cdecap18 cdecap19 cdecap20 +$frame cdecap21 cdecap22 cdecap23 cdecap24 cdecap25 +$frame cdecap26 cdecap27 cdecap28 + +// +$frame cdeath1 cdeath2 cdeath3 cdeath4 cdeath5 +$frame cdeath6 cdeath7 cdeath8 cdeath9 cdeath10 +$frame cdeath11 cdeath12 cdeath13 cdeath14 cdeath15 +$frame cdeath16 cdeath17 cdeath18 cdeath19 cdeath20 + +// +$frame flyham1 flyham2 flyham3 flyham4 flyham5 +$frame flyham6 flyham7 flyham8 flyham9 flyham10 +$frame flyham11 flyham12 flyham13 flyham14 flyham15 + +// +$frame attham1 attham2 attham3 attham4 attham5 +$frame attham6 attham7 attham8 attham9 attham10 + +// +$frame painham1 painham2 painham3 painham4 painham5 +$frame painham6 painham7 painham8 + +// +$frame stdham1 stdham2 stdham3 stdham4 stdham5 +$frame stdham6 stdham7 stdham8 stdham9 stdham10 +$frame stdham11 stdham12 stdham13 + +// +$frame runham1 runham2 runham3 runham4 runham5 +$frame runham6 runham7 runham8 runham9 runham10 +$frame runham11 runham12 + +// +$frame flyice1 flyice2 flyice3 flyice4 flyice5 +$frame flyice6 flyice7 flyice8 flyice9 flyice10 +$frame flyice11 flyice12 flyice13 flyice14 flyice15 + +// +$frame painice1 painice2 painice3 painice4 painice5 +$frame painice6 painice7 painice8 + +// +$frame runice1 runice2 runice3 runice4 runice5 +$frame runice6 runice7 runice8 runice9 runice10 +$frame runice11 runice12 + +// +$frame attice1 attice2 attice3 attice4 + +// +$frame stdice1 stdice2 stdice3 stdice4 stdice5 +$frame stdice6 stdice7 stdice8 stdice9 stdice10 +$frame stdice11 stdice12 stdice13 + +// +$frame cjump1 cjump2 cjump3 cjump4 cjump5 +$frame cjump6 cjump7 cjump8 cjump9 cjump10 +$frame cjump11 cjump12 cjump13 + +// +$frame cflystf1 cflystf2 cflystf3 cflystf4 cflystf5 +$frame cflystf6 cflystf7 cflystf8 cflystf9 cflystf10 +$frame cflystf11 cflystf12 cflystf13 cflystf14 cflystf15 + +// +$frame cpainstf1 cpainstf2 cpainstf3 cpainstf4 cpainstf5 +$frame cpainstf6 cpainstf7 cpainstf8 + +// +$frame crunstf1 crunstf2 crunstf3 crunstf4 crunstf5 +$frame crunstf6 crunstf7 crunstf8 crunstf9 crunstf10 +$frame crunstf11 crunstf12 + +// +$frame cattstf1 cattstf2 cattstf3 cattstf4 cattstf5 + +// +$frame cstdstf1 cstdstf2 cstdstf3 cstdstf4 cstdstf5 +$frame cstdstf6 cstdstf7 cstdstf8 cstdstf9 cstdstf10 +$frame cstdstf11 cstdstf12 cstdstf13 + + +//================================================================= +$framevalue 0 + +//NECROMANCER +// +$frame ncrouch1 ncrouch2 ncrouch3 ncrouch4 ncrouch5 +$frame ncrouch6 ncrouch7 ncrouch8 ncrouch9 ncrouch10 +$frame ncrouch11 ncrouch12 ncrouch13 ncrouch14 ncrouch15 +$frame ncrouch16 ncrouch17 ncrouch18 ncrouch19 ncrouch20 + +// +$frame ndeath1 ndeath2 ndeath3 ndeath4 ndeath5 +$frame ndeath6 ndeath7 ndeath8 ndeath9 ndeath10 +$frame ndeath11 ndeath12 ndeath13 ndeath14 ndeath15 +$frame ndeath16 ndeath17 ndeath18 ndeath19 ndeath20 + +// +$frame ndecap1 ndecap2 ndecap3 ndecap4 ndecap5 +$frame ndecap6 ndecap7 ndecap8 ndecap9 ndecap10 +$frame ndecap11 ndecap12 ndecap13 ndecap14 ndecap15 +$frame ndecap16 ndecap17 ndecap18 ndecap19 ndecap20 + +// +$frame atthan1 atthan2 atthan3 atthan4 atthan5 +$frame atthan6 atthan7 atthan8 + +// +$frame flyhan1 flyhan2 flyhan3 flyhan4 flyhan5 +$frame flyhan6 flyhan7 flyhan8 flyhan9 flyhan10 +$frame flyhan11 flyhan12 flyhan13 flyhan14 flyhan15 + +// +$frame painhan1 painhan2 painhan3 painhan4 painhan5 +$frame painhan6 painhan7 painhan8 + +// +$frame runhan1 runhan2 runhan3 runhan4 runhan5 +$frame runhan6 runhan7 runhan8 runhan9 runhan10 +$frame runhan11 runhan12 + +// +$frame stdhan1 stdhan2 stdhan3 stdhan4 stdhan5 +$frame stdhan6 stdhan7 stdhan8 stdhan9 stdhan10 +$frame stdhan11 stdhan12 + +// +$frame attsic1 attsic2 attsic3 attsic4 attsic5 +$frame attsic6 attsic7 attsic8 attsic9 attsic10 +$frame attsic11 attsic12 + +// +$frame flysic1 flysic2 flysic3 flysic4 flysic5 +$frame flysic6 flysic7 flysic8 flysic9 flysic10 +$frame flysic11 flysic12 flysic13 flysic14 flysic15 + +// +$frame painsic1 painsic2 painsic3 painsic4 painsic5 +$frame painsic6 painsic7 painsic8 + +// +$frame runsic1 runsic2 runsic3 runsic4 runsic5 +$frame runsic6 runsic7 runsic8 runsic9 runsic10 +$frame runsic11 runsic12 + +// +$frame stdsic1 stdsic2 stdsic3 stdsic4 stdsic5 +$frame stdsic6 stdsic7 stdsic8 stdsic9 stdsic10 +$frame stdsic11 stdsic12 + +// +$frame nattstf1 nattstf2 nattstf3 nattstf4 nattstf5 +$frame nattstf6 nattstf7 nattstf8 + +// +$frame nflystf1 nflystf2 nflystf3 nflystf4 nflystf5 +$frame nflystf6 nflystf7 nflystf8 nflystf9 nflystf10 +$frame nflystf11 nflystf12 nflystf13 nflystf14 nflystf15 + +// +$frame npainstf1 npainstf2 npainstf3 npainstf4 npainstf5 +$frame npainstf6 npainstf7 npainstf8 + +// +$frame nrunstf1 nrunstf2 nrunstf3 nrunstf4 nrunstf5 +$frame nrunstf6 nrunstf7 nrunstf8 nrunstf9 nrunstf10 +$frame nrunstf11 nrunstf12 + +// +$frame nstdstf1 nstdstf2 nstdstf3 nstdstf4 nstdstf5 +$frame nstdstf6 nstdstf7 nstdstf8 nstdstf9 nstdstf10 +$frame nstdstf11 nstdstf12 + + +//================================================================= +$framevalue 0 + +//ASSASSIN +// +$frame attdag1 attdag2 attdag3 attdag4 attdag5 +$frame attdag6 attdag7 attdag8 attdag9 attdag10 +$frame attdag11 + +// +$frame aattstf1 aattstf2 aattstf3 aattstf4 + +// +$frame attxbw1 attxbw2 attxbw3 attxbw4 + +// +$frame acrouch1 acrouch2 acrouch3 acrouch4 acrouch5 +$frame acrouch6 acrouch7 acrouch8 acrouch9 acrouch10 +$frame acrouch11 acrouch12 acrouch13 acrouch14 acrouch15 +$frame acrouch16 acrouch17 acrouch18 acrouch19 acrouch20 + +// +$frame adeath1 adeath2 adeath3 adeath4 adeath5 +$frame adeath6 adeath7 adeath8 adeath9 adeath10 +$frame adeath11 adeath12 adeath13 adeath14 adeath15 +$frame adeath16 adeath17 adeath18 adeath19 adeath20 + +// +$frame adecap1 adecap2 adecap3 adecap4 adecap5 +$frame adecap6 adecap7 adecap8 adecap9 adecap10 +$frame adecap11 adecap12 adecap13 adecap14 adecap15 +$frame adecap16 adecap17 adecap18 adecap19 adecap20 +$frame adecap21 adecap22 adecap23 adecap24 adecap25 +$frame adecap26 adecap27 adecap28 + +// +$frame flydag1 flydag2 flydag3 flydag4 flydag5 +$frame flydag6 flydag7 flydag8 flydag9 flydag10 +$frame flydag11 flydag12 flydag13 flydag14 flydag15 + +// +$frame aflystf1 aflystf2 aflystf3 aflystf4 aflystf5 +$frame aflystf6 aflystf7 aflystf8 aflystf9 aflystf10 +$frame aflystf11 aflystf12 aflystf13 aflystf14 aflystf15 + +// +$frame flyxbw1 flyxbw2 flyxbw3 flyxbw4 flyxbw5 +$frame flyxbw6 flyxbw7 flyxbw8 flyxbw9 flyxbw10 +$frame flyxbw11 flyxbw12 flyxbw13 flyxbw14 flyxbw15 + +// +$frame ajump1 ajump2 ajump3 ajump4 ajump5 +$frame ajump6 ajump7 ajump8 ajump9 ajump10 +$frame ajump11 ajump12 + +// +$frame paindag1 paindag2 paindag3 paindag4 paindag5 +$frame paindag6 paindag7 + +// +$frame apainstf1 apainstf2 apainstf3 apainstf4 apainstf5 +$frame apainstf6 apainstf7 + +// +$frame painxbw1 painxbw2 painxbw3 painxbw4 painxbw5 +$frame painxbw6 painxbw7 + +// +$frame rundag1 rundag2 rundag3 rundag4 rundag5 +$frame rundag6 rundag7 rundag8 rundag9 rundag10 +$frame rundag11 rundag12 + +// +$frame arunstf1 arunstf2 arunstf3 arunstf4 arunstf5 +$frame arunstf6 arunstf7 arunstf8 arunstf9 arunstf10 +$frame arunstf11 arunstf12 + +// +$frame runxbw1 runxbw2 runxbw3 runxbw4 runxbw5 +$frame runxbw6 runxbw7 runxbw8 runxbw9 runxbw10 +$frame runxbw11 runxbw12 + +// +$frame stddag1 stddag2 stddag3 stddag4 stddag5 +$frame stddag6 stddag7 stddag8 stddag9 stddag10 +$frame stddag11 stddag12 stddag13 + +// +$frame astdstf1 astdstf2 astdstf3 astdstf4 astdstf5 +$frame astdstf6 astdstf7 astdstf8 astdstf9 astdstf10 +$frame astdstf11 astdstf12 astdstf13 + +// +$frame stdxbw1 stdxbw2 stdxbw3 stdxbw4 stdxbw5 +$frame stdxbw6 stdxbw7 stdxbw8 stdxbw9 stdxbw10 +$frame stdxbw11 stdxbw12 stdxbw13 + + +//================================================================= +$framevalue 0 + +//SUCCUBUS +// +// +$frame runwpa1 runwpa2 runwpa3 runwpa4 runwpa5 +$frame runwpa6 runwpa7 runwpa8 runwpa9 runwpa10 +$frame runwpa11 runwpa12 + +// +$frame runwpbc1 runwpbc2 runwpbc3 runwpbc4 runwpbc5 +$frame runwpbc6 runwpbc7 runwpbc8 runwpbc9 runwpbc10 +$frame runwpbc11 runwpbc12 + +// +$frame runwpd1 runwpd2 runwpd3 runwpd4 runwpd5 +$frame runwpd6 runwpd7 runwpd8 runwpd9 runwpd10 +$frame runwpd11 runwpd12 + +// +$frame wtwpa1 wtwpa2 wtwpa3 wtwpa4 wtwpa5 +$frame wtwpa6 wtwpa7 wtwpa8 wtwpa9 wtwpa10 +$frame wtwpa11 wtwpa12 wtwpa13 + +// +$frame wtwpbc1 wtwpbc2 wtwpbc3 wtwpbc4 wtwpbc5 +$frame wtwpbc6 wtwpbc7 wtwpbc8 wtwpbc9 wtwpbc10 +$frame wtwpbc11 wtwpbc12 wtwpbc13 + +// +$frame wtwpd1 wtwpd2 wtwpd3 wtwpd4 wtwpd5 +$frame wtwpd6 wtwpd7 wtwpd8 wtwpd9 wtwpd10 +$frame wtwpd11 wtwpd12 wtwpd13 + +// +$frame atwpa1 atwpa2 atwpa3 atwpa4 atwpa5 +$frame atwpa6 atwpa7 atwpa8 + +// +$frame atwpbc1 atwpbc2 atwpbc3 atwpbc4 +$frame atwpbc5 atwpbc6 atwpbc7 atwpbc8 + +// +$frame atwpd1 atwpd2 atwpd3 atwpd4 +$frame atwpd5 atwpd6 atwpd7 atwpd8 + +// +$frame pnwpa1 pnwpa2 pnwpa3 pnwpa4 pnwpa5 +$frame pnwpa6 pnwpa7 + +// +$frame pnwpbc1 pnwpbc2 pnwpbc3 pnwpbc4 pnwpbc5 +$frame pnwpbc6 pnwpbc7 + +// +$frame pnwpd1 pnwpd2 pnwpd3 pnwpd4 pnwpd5 +$frame pnwpd6 pnwpd7 + +// +$frame swmwpa1 swmwpa2 swmwpa3 swmwpa4 swmwpa5 +$frame swmwpa6 swmwpa7 swmwpa8 swmwpa9 swmwpa10 +$frame swmwpa11 swmwpa12 swmwpa13 swmwpa14 swmwpa15 + +// +$frame swmwpbc1 swmwpbc2 swmwpbc3 swmwpbc4 swmwpbc5 +$frame swmwpbc6 swmwpbc7 swmwpbc8 swmwpbc9 swmwpbc10 +$frame swmwpbc11 swmwpbc12 swmwpbc13 swmwpbc14 swmwpbc15 + +// +$frame swmwpd1 swmwpd2 swmwpd3 swmwpd4 swmwpd5 +$frame swmwpd6 swmwpd7 swmwpd8 swmwpd9 swmwpd10 +$frame swmwpd11 swmwpd12 swmwpd13 swmwpd14 swmwpd15 + +// +$frame djump1 djump2 djump3 djump4 djump5 +$frame djump6 djump7 djump8 djump9 djump10 +$frame djump11 djump12 djump13 djump14 djump15 + +// +$frame dcrouch1 dcrouch2 dcrouch3 dcrouch4 dcrouch5 +$frame dcrouch6 dcrouch7 dcrouch8 dcrouch9 dcrouch10 +$frame dcrouch11 dcrouch12 dcrouch13 dcrouch14 dcrouch15 +$frame dcrouch16 dcrouch17 dcrouch18 dcrouch19 dcrouch20 + +// +$frame ddeath1 ddeath2 ddeath3 ddeath4 ddeath5 +$frame ddeath6 ddeath7 ddeath8 ddeath9 ddeath10 +$frame ddeath11 ddeath12 ddeath13 ddeath14 ddeath15 +$frame ddeath16 ddeath17 ddeath18 ddeath19 ddeath20 + +// +$frame ddecap1 ddecap2 ddecap3 ddecap4 ddecap5 +$frame ddecap6 ddecap7 ddecap8 ddecap9 ddecap10 +$frame ddecap11 ddecap12 ddecap13 ddecap14 ddecap15 +$frame ddecap16 ddecap17 ddecap18 ddecap19 ddecap20 +$frame ddecap21 ddecap22 ddecap23 ddecap24 ddecap25 +$frame ddecap26 ddecap27 ddecap28 + +//================================================================= +$framevalue 0 + +//Dwarf +// +// +$frame axestd1 axestd2 axestd3 axestd4 axestd5 +$frame axestd6 axestd7 axestd8 axestd9 axestd10 +$frame axestd11 axestd12 axestd13 axestd14 axestd15 +$frame axestd16 axestd17 axestd18 axestd19 axestd20 +$frame axestd21 axestd22 axestd23 axestd24 + +// +$frame hmrstd1 hmrstd2 hmrstd3 hmrstd4 hmrstd5 +$frame hmrstd6 hmrstd7 hmrstd8 hmrstd9 hmrstd10 +$frame hmrstd11 hmrstd12 hmrstd13 hmrstd14 hmrstd15 +$frame hmrstd16 hmrstd17 hmrstd18 hmrstd19 hmrstd20 +$frame hmrstd21 hmrstd22 hmrstd23 hmrstd24 + +// +$frame axerun1 axerun2 axerun3 axerun4 axerun5 +$frame axerun6 axerun7 axerun8 axerun9 axerun10 +$frame axerun11 axerun12 + +// +$frame hmrrun1 hmrrun2 hmrrun3 hmrrun4 hmrrun5 +$frame hmrrun6 hmrrun7 hmrrun8 hmrrun9 hmrrun10 +$frame hmrrun11 hmrrun12 + +// +$frame axehit1 axehit2 axehit3 axehit4 axehit5 +$frame axehit6 axehit7 axehit8 axehit9 axehit10 +$frame axehit11 axehit12 + +// +$frame hmrhit1 hmrhit2 hmrhit3 hmrhit4 hmrhit5 +$frame hmrhit6 hmrhit7 hmrhit8 hmrhit9 hmrhit10 +$frame hmrhit11 hmrhit12 + +// +$frame axepain1 axepain2 axepain3 axepain4 axepain5 +$frame axepain6 axepain7 axepain8 + +// +$frame hmrpain1 hmrpain2 hmrpain3 hmrpain4 hmrpain5 +$frame hmrpain6 hmrpain7 hmrpain8 + +// +$frame axeswm1 axeswm2 axeswm3 axeswm4 axeswm5 +$frame axeswm6 axeswm7 axeswm8 axeswm9 axeswm10 +$frame axeswm11 axeswm12 axeswm13 axeswm14 axeswm15 + +// +$frame hmrswm1 hmrswm2 hmrswm3 hmrswm4 hmrswm5 +$frame hmrswm6 hmrswm7 hmrswm8 hmrswm9 hmrswm10 +$frame hmrswm11 hmrswm12 hmrswm13 hmrswm14 hmrswm15 + +// +$frame hdeath1 hdeath2 hdeath3 hdeath4 hdeath5 +$frame hdeath6 hdeath7 hdeath8 hdeath9 hdeath10 +$frame hdeath11 hdeath12 hdeath13 hdeath14 hdeath15 +$frame hdeath16 hdeath17 hdeath18 hdeath19 hdeath20 + +// +$frame hdecap1 hdecap2 hdecap3 hdecap4 hdecap5 +$frame hdecap6 hdecap7 hdecap8 hdecap9 hdecap10 +$frame hdecap11 hdecap12 hdecap13 hdecap14 hdecap15 +$frame hdecap16 hdecap17 hdecap18 hdecap19 hdecap20 +$frame hdecap21 hdecap22 hdecap23 hdecap24 + +// +$frame hjump1 hjump2 hjump3 hjump4 hjump5 +$frame hjump6 hjump7 hjump8 hjump9 hjump10 +$frame hjump11 hjump12 hjump13 + +//================================================================= +$framevalue 0 + +//BEAST +// +$frame charge + +$frame wait + +$frame walk + +// +$frame death01 death02 death03 death04 death05 +$frame death06 death07 death08 death09 death10 +$frame death11 death12 death13 death14 death15 +$frame death16 death17 death18 death19 death20 +$frame death21 death22 death23 death24 death25 + +// +$frame gorech01 gorech02 gorech03 gorech04 gorech05 +$frame gorech06 gorech07 gorech08 gorech09 gorech10 +$frame gorech11 gorech12 + +// +$frame howl01 howl02 howl03 howl04 howl05 +$frame howl06 howl07 howl08 howl09 howl10 +$frame howl11 howl12 howl13 howl14 howl15 +$frame howl16 howl17 howl18 howl19 howl20 +$frame howl21 howl22 howl23 howl24 howl25 +$frame howl26 howl27 howl28 howl29 howl30 +$frame howl31 howl32 howl33 howl34 howl35 +$frame howl36 + +// +$frame jump01 jump02 jump03 jump04 jump05 +$frame jump06 jump07 jump08 jump09 jump10 +$frame jump11 jump12 jump13 jump14 jump15 +$frame jump16 jump17 jump18 jump19 jump20 +$frame jump21 jump22 jump23 jump24 + +// +$frame pain1 pain2 pain3 pain4 pain5 +$frame pain6 pain7 pain8 + +// +$frame shake01 shake02 shake03 shake04 shake05 +$frame shake06 shake07 shake08 shake09 shake10 +$frame shake11 shake12 shake13 shake14 shake15 +$frame shake16 shake17 shake18 shake19 shake20 + +// +$frame shard01 shard02 shard03 shard04 shard05 +$frame shard06 shard07 shard08 shard09 shard10 +$frame shard11 shard12 shard13 shard14 shard15 +$frame shard16 shard17 shard18 shard19 shard20 +$frame shard21 shard22 shard23 shard24 shard25 +$frame shard26 shard27 shard28 shard29 shard30 +$frame shard31 shard32 + +// +$frame slidel + +// +$frame slider + +/* +============================== +CONSTANTS: (in constants.hc) +============================== +float ACT_STAND = 0; +float ACT_RUN = 1; +float ACT_SWIM_FLY = 2; +float ACT_ATTACK = 3; +float ACT_PAIN = 4; + +float ACT_JUMP = 5;//Rest of these not weapon dep. (except nec jump) +float ACT_CROUCH_STAND = 6; +float ACT_CROUCH_MOVE = 7; +float ACT_DEAD = 8; +float ACT_DECAP = 9; + +//Beast +float ACT_YAK_HIT = 2; +float ACT_YAK_HOWL = 9; +*/ + +void Pal_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1) + self.th_missile=pal_vorpal_fire; + else if(self.weapon==IT_WEAPON2) + self.th_missile=pal_axe_fire; + else if(self.weapon==IT_WEAPON3) + self.th_missile=crossbow_fire; +} + +void Dwf_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON2) + self.th_missile=pal_axe_fire; + else if(self.weapon==IT_WEAPON1) + self.th_missile=Cru_Wham_Fire; +} + +void Cru_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1) + self.th_missile=Cru_Wham_Fire; + else + self.th_missile=SUB_Null; + +} + +void Nec_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1) + self.th_missile=sickle_decide_attack; + else if(self.weapon==IT_WEAPON2) + self.th_missile=crossbow_fire; + else + self.th_missile=Nec_Mis_Attack; +} + +void Ass_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON2||self.weapon==IT_WEAPON3) + self.th_missile=crossbow_fire; + else if(self.weapon==IT_WEAPON4) + self.th_missile=Use_Tripwire;//grenade_throw; + else + self.th_missile=Ass_Pdgr_Fire; +} + +void Suc_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON2) + self.th_missile=pal_vorpal_fire; + else if(self.weapon==IT_WEAPON3) + self.th_missile=crossbow_fire; + else if(self.weapon==IT_WEAPON4) + self.th_missile=grenade_throw; + else + self.th_missile=Suc_Blrn_Fire; +} + +float player_start_frames[280] = +{ +//Stand + $stdswd1 ,$stdswd1 ,$stdgnt1 ,$stdgnt1 , //Paladin + $stdham1 ,$stdice1 ,$stdice1 ,$stdice1 , //Crusader + $stdsic1 ,$stdhan1 ,$stdhan1 ,$stdhan1 , //Necromancer + $stddag1 ,$stdxbw1 ,$stdxbw1 ,$stddag1 , //Assassin + $wtwpa1 ,$wtwpbc1 ,$wtwpbc1 ,$wtwpd1 , //Succubus + $hmrstd1 ,$axestd1 ,$axestd1 ,$axestd1 , //Dwarf + $wait,0,0,0, //BEAST +//Run + $runswd1,$runswd1,$rungnt1,$rungnt1, //Paladin + $runham1,$runice1,$runice1,$runice1, //Crusader + $runsic1,$runhan1,$runhan1,$runhan1, //Necromancer + $rundag1,$runxbw1,$rundag1,$rundag1, //Assassin + $runwpa1,$runwpbc1,$runwpbc1,$runwpd1, //Succubus + $hmrrun1 ,$axerun1 ,$axerun1 ,$axerun1 , //Dwarf + $walk,0,0,0, //BEAST +//Swim/fly + $flyswd1,$flyswd1,$flygnt1,$flygnt1, //Paladin + $flyham1,$flyice1,$flyice1,$flyice1, //Crusader + $flysic1,$flyhan1,$flyhan1,$flyhan1, //Necromancer + $flydag1,$flyxbw1,$flydag1,$flydag1, //Assassin + $swmwpa1,$swmwpbc1,$swmwpbc1,$swmwpd1, //Succubus + $hmrswm1 ,$axeswm1 ,$axeswm1 ,$axeswm1 , //Dwarf + $gorech01, $gorech01, $gorech01, $gorech01, //BEAST +//Attack + $attswd1,$attswd1,$attgnt1,$attgnt1, //Paladin + $attham1,$attice1,$attice1,$attice1, //Crusader + $attsic1,$atthan1,$atthan1,$atthan1, //Necromancer + $attdag1,$attxbw1,$attxbw1,$attdag1, //Assassin + $atwpa1,$atwpbc1,$atwpbc1,$atwpd1, //Succubus + $hmrhit1 ,$axehit1 ,$axehit1 ,$axehit1 , //Dwarf + $charge,0,0,0, //BEAST +//pain + $painswd1,$painswd1,$paingnt1,$paingnt1, //Paladin + $painham1,$painice1,$painice1,$painice1, //Crusader + $painsic1,$painhan1,$painhan1,$painhan1, //Necromancer + $paindag1,$painxbw1,$painxbw1,$paindag1, //Assassin + $pnwpa1,$pnwpbc1,$pnwpbc1,$pnwpd1, //Succubus + $hmrpain1 ,$axepain1 ,$axepain1 ,$axepain1 , //Dwarf + $pain1,0,0,0, //BEAST +//Jump + $pjump1,0,0,0, //Paladin + $cjump1,0,0,0, //Crusader + $runsic1,$runhan1,$runhan1,$runhan1, //Necromancer + $ajump1,0,0,0, //Assassin + $djump1,0,0,0, //Succubus + $hjump1,0,0,0, //Dwarf + $jump01,0,0,0, //BEAST +//Crouch_stand + $pcrouch1,0,0,0, //Paladin + $ccrouch1,0,0,0, //Crusader + $ncrouch1,0,0,0, //Necromancer + $acrouch1,0,0,0, //Assassin + $dcrouch1,0,0,0, //Succubus + 0,0,0,0, //Dwarf + 0,0,0,0, //BEAST +//Crouch_move + $pcrouch1,0,0,0, //Paladin + $ccrouch1,0,0,0, //Crusader + $ncrouch1,0,0,0, //Necromancer + $acrouch1,0,0,0, //Assassin + $dcrouch1,0,0,0, //Succubus + 0,0,0,0, //Dwarf + 0,0,0,0, +//dead + $pdeath1,0,0,0, //Paladin + $cdeath1,0,0,0, //Crusader + $ndeath1,0,0,0, //Necromancer + $adeath1,0,0,0, //Assassin + $ddeath1,0,0,0, //Succubus + $hdeath1,0,0,0, //Dwarf + $death01,0,0,0, //BEAST +//decap + $pdecap1,0,0,0, //Paladin + $cdecap1,0,0,0, //Crusader + $ndecap1,0,0,0, //Necromancer + $adecap1,0,0,0, //Assassin + $ddecap1,0,0,0, //Succubus + $hdecap1,0,0,0, //Dwarf + $howl01,0,0,0 //BEAST +}; + +float player_end_frames[280] = +{ +//Stand + $stdswd13,$stdswd13,$stdgnt13,$stdgnt13, //Paladin + $stdham13,$stdice13,$stdice13,$stdice13, //Crusader + $stdsic12,$stdhan12,$stdhan12,$stdhan12, //Necromancer + $stddag13,$stdxbw13,$stdxbw13,$stddag13, //Assassin + $wtwpa13,$wtwpbc13,$wtwpbc13,$wtwpd13, //Succubus + $hmrstd24 ,$axestd24 ,$axestd24 ,$axestd24 ,//Dwarf + $wait,0,0,0, //BEAST +//Run + $runswd12,$runswd12,$rungnt12,$rungnt12, //Paladin + $runham12,$runice12,$runice12,$runice12, //Crusader + $runsic12,$runhan12,$runhan12,$runhan12, //Necromancer + $rundag12,$runxbw12,$runxbw12,$rundag12, //Assassin + $runwpa12,$runwpbc12,$runwpbc12,$runwpd12, //Succubus + $hmrrun12 ,$axerun12 ,$axerun12 ,$axerun12 ,//Dwarf + $walk,0,0,0, //BEAST +//Swim/fly + $flyswd15,$flyswd15,$flygnt15,$flygnt15, //Paladin + $flyham15,$flyice15,$flyice15,$flyice15, //Crusader + $flysic14,$flyhan14,$flyhan14,$flyhan14, //Necromancer + $flydag15,$flyxbw15,$flyxbw15,$flydag15, //Assassin + $swmwpa15,$swmwpbc15,$swmwpbc15,$swmwpd15, //Succubus + $hmrswm15 ,$axeswm15 ,$axeswm15 ,$axeswm15 ,//Dwarf + $gorech12, $gorech12, $gorech12, $gorech12, //BEAST +//Attack + $attswd12,$attswd12,$attgnt11,$attgnt11, //Paladin + $attham10,$attice4,$attice4,$attice4, //Crusader + $attsic12,$atthan8,$atthan8,$atthan8, //Necromancer + $attdag11,$attxbw4,$attxbw4,$attdag11, //Assassin + $atwpa8,$atwpbc8,$atwpbc8,$atwpd8, //Succubus + $hmrhit12 ,$axehit12 ,$axehit12 ,$axehit12 ,//Dwarf + $charge,0,0,0, //BEAST +//pain + $painswd7,$painswd7,$paingnt7,$paingnt7, //Paladin + $painham8,$painice8,$painice8,$painice8, //Crusader + $painsic8,$painhan8,$painhan8,$painhan8, //Necromancer + $paindag7,$painxbw7,$painxbw7,$paindag7, //Assassin + $pnwpa7,$pnwpbc7,$pnwpbc7,$pnwpd7, //Succubus + $hmrpain8 ,$axepain8 ,$axepain8 ,$axepain8 ,//Dwarf + $pain8,0,0,0, //BEAST +//Jump + $pjump12,0,0,0, //Paladin + $cjump13,0,0,0, //Crusader + $runsic12,$runhan12,$runhan12,$runhan12, //Necromancer + $ajump12,0,0,0, //Assassin + $djump15,0,0,0, //Succubus + $hjump13,0,0,0, //Dwarf + $jump24,0,0,0, //BEAST +//Crouch_stand + $pcrouch20,0,0,0, //Paladin + $ccrouch20,0,0,0, //Crusader + $ncrouch20,0,0,0, //Necromancer + $acrouch20,0,0,0, //Assassin + $dcrouch20,0,0,0, //Succubus + 0,0,0,0, //Dwarf + 0,0,0,0, //BEAST +//Crouch_move + $pcrouch20,0,0,0, //Paladin + $ccrouch20,0,0,0, //Crusader + $ncrouch20,0,0,0, //Necromancer + $acrouch20,0,0,0, //Assassin + $dcrouch20,0,0,0, //Succubus + 0,0,0,0, //Dwarf + 0,0,0,0, //BEAST +//dead + $pdeath20,0,0,0, //Paladin + $cdeath20,0,0,0, //Crusader + $ndeath20,0,0,0, //Necromancer + $adeath20,0,0,0, //Assassin + $ddeath20,0,0,0, //Succubus + $hdeath20,0,0,0, //Dwarf + $death25,0,0,0, //BEAST +//decap + $pdecap28,0,0,0, //Paladin + $cdecap28,0,0,0, //Crusader + $ndecap20,0,0,0, //Necromancer + $adecap28,0,0,0, //Assassin + $ddecap28,0,0,0, //Succubus + $hdecap24,0,0,0, //Dwarf + $howl36,0,0,0 //BEAST +}; + +void fstep_fade_out (void) +{ + if(self.colormap<159+256) + { + self.colormap+=1; + thinktime self : 0.05; + } + else + remove(self); +} + +void dropStep (void) +{ +entity fstep,oself; +vector org; + makevectors(self.angles); + if(self.lefty) + org=self.origin-v_right*8; + else + org=self.origin+v_right*8; + + traceline(org+'0 0 2',org - '0 0 16',TRUE,self); + if(trace_plane_normal=='0 0 0') + return; + + fstep=spawn(); + setorigin(fstep,trace_endpos+'0 0 1'); + fstep.angles_y=self.angles_y; + oself=self; + self=fstep; + pitch_roll_for_slope(trace_plane_normal); + self=oself; + if(self.lefty) + { + fstep.angles_z+=180; + self.lefty=FALSE; + } + else + self.lefty=TRUE; + setmodel(fstep,"models/fstep.mdl"); + fstep.drawflags(+)DRF_TRANSLUCENT; + fstep.colormap= 144+256; + particle4(trace_endpos+'0 0 8',16,fstep.colormap,PARTICLETYPE_BLUESTEP,random(5,10)); + fstep.abslight = 0.5; + fstep.think=fstep_fade_out; + thinktime fstep : 0.5; +} + +void player_frames () +{ +float weapmod, startframe,endframe,framestate,dot,am_beast,class_val,skip_anim; +vector move_dir; +/* + if(self.playerclass==CLASS_DWARF&&random()<0.1) + { + dprintf("Hank's actstate: %s\n",self.act_state); + dprintf("Hank's frame is: %s\n",self.frame); + } +*/ + + if(self.deadflag) + self.act_state=ACT_DEAD; + + if(self.model=="models/yakman.mdl") + am_beast=TRUE; + + if(am_beast) + { + if(self.hull!=HULL_GOLEM) + sprint(self,PRINT_HIGH,"ERROR! HULL not beast!\n"); + if(self.mins!='-48 -48 -50'||self.maxs!='48 48 50') + sprint(self,PRINT_HIGH,"ERROR! Size not beast size!\n"); + + if(self.act_state==ACT_ATTACK) + self.hasted=2; + else + self.hasted=1; + + weapmod=0; + class_val=7; + if(self.act_state==ACT_RUN) + { + self.view_ofs='0 0 72'; + self.frame=$walk; + if(self.cnt>=7) + { + sound(self,CHAN_AUTO,"eidolon/stomp.wav",1,ATTN_NORM); + self.cnt=0; + } + else + self.cnt+=1; +/* if(self.t_width0.5) + self.frame=$slider; + else if(dot<-0.5) + self.frame=$slidel; + } + skip_anim=TRUE; + } + else + { + self.view_ofs='0 0 100'; + if(self.act_state==ACT_STAND) + { + self.frame=$wait; + skip_anim=TRUE; + } + else if(self.act_state==ACT_ATTACK) + { + self.frame=$charge; + skip_anim=TRUE; + } + } + } + else + { + if(self.catapult_time>time&&!(self.flags&FL_ONGROUND))//launched by a catapult + self.act_state=ACT_SWIM_FLY; + class_val=self.playerclass; + if(self.act_state0.5) + dropStep(); + + + if(self.act_state!=ACT_DEAD) + if((self.viewentity==self||self.viewentity.classname=="chasecam")&&self.camera_timeendframe || self.frame$djump9) + self.frame=$djump9; + + if(framestate==AF_END&&!self.button0) + { + if(!self.velocity_x && !self.velocity_y) + self.act_state=ACT_STAND; + else + self.act_state=ACT_RUN; + } + } + else if(self.act_state==ACT_YAK_HOWL&&am_beast) + { + if(framestate==AF_END) + self.act_state=ACT_STAND; + } + + if(self.act_state==ACT_DEAD) + { + if(self.frame==startframe&&!deathmatch) + if(self.enemy.flags2&FL_ALIVE&&visible(self.enemy)) + self.pausetime=time+3; + + if(self.view_ofs_z - 2.5 >= 8)//Drop view + self.view_ofs_z-=2.5; + + if(framestate==AF_END) + { + self.view_ofs='0 0 8'; + self.think=PlayerDead; + thinktime self : 0; + } + } + else if(self.waterlevel>2||self.movetype==MOVETYPE_FLY)//overrides all others + if(!am_beast) + self.act_state=ACT_SWIM_FLY; +} + +void player_frames_behead () +{//Note: give playerclass! + self.level=player_start_frames[ACT_DECAP * 28 + (self.playerclass - 1) * 4]; + self.dmg=player_end_frames[ACT_DECAP * 28 + (self.playerclass - 1) * 4]; + self.cnt=0; + player_behead(); +} + diff --git a/object.hc b/object.hc new file mode 100644 index 0000000..d5374db --- /dev/null +++ b/object.hc @@ -0,0 +1,2174 @@ +/* + * $Header: /HexenWorld/Siege/object.hc 13 5/31/98 2:59p Mgummelt $ + */ + + +float SPAWNFLAG_BALLISTA_TRACK = 1; + +/* + * obj_push() -- Allows players to push objects when they walk toward them. + */ +void() Missile_Arc; +void(float vol) sheep_sound; +void() obj_barrel_roll; +void()float; +void()sheep_trot; + +void fix_vel () +{ + self.enemy.velocity=self.mangle; + remove(self); +} + +void obj_fly_hurt (entity loser) +{//MG +//FIXME: Check for sky +//dprint("hit\n"); +float magnitude,my_mass; + if(self.classname=="player_sheep"&&self.teleport_time+10&&other.classname=="snowball") + return; + + if(self.classname=="player") + { + my_mass=self.mass; + } + else + { + if(!self.mass) + my_mass = 1; + else if(self.mass<=10) + my_mass=10; + else + my_mass = self.mass/10; + } + + magnitude=vlen(self.velocity)*my_mass/10; + if(pointcontents(self.absmax)==CONTENT_WATER)//FIXME: or other watertypes + magnitude/=3; //water absorbs 2/3 velocity + + if(self.classname=="barrel"&&self.aflag)//rolling barrels are made for impacts! + magnitude*=3; + + if(self.frozen>0&&magnitude<300&&self.flags&FL_ONGROUND&&loser==world&&self.velocity_z<-20&&self.last_onground+0.3 "); + dprint(loser.classname); + dprint("\n"); + dprint(vtos(self.velocity)); + dprint("\n"); + dprint("Magnitude: "); + dprint(ftos(magnitude)); + dprint("\n"); + dprint("Air time: "); + dprint(ftos(time-self.last_onground)); + dprint("\n"); + dprint("Time since last impact: "); + dprint(ftos(time-self.last_impact)); + dprint("\n"); + } +*/ + if(self.last_onground+0.3=THINGTYPE_GLASS)) + { + vector dir1, dir2; + float force,dot; + if(loser.thingtype>=THINGTYPE_GLASS) + magnitude*=2; + + if(magnitude>=100&&loser.takedamage&&loser.classname!="catapult"&&loser!=world) + { + + dir1=normalize(self.velocity); + if(loser.origin=='0 0 0') + dir2=dir1; + else + dir2=normalize(loser.origin-self.origin); + + dot= dir1*dir2; + + if(dot >= 0.2) + force=dot; + else + force=0; + + force*=magnitude/50; + + if(pointcontents(loser.absmax)==CONTENT_WATER||(self.classname=="barrel"&&self.aflag))//FIXME: or other watertypes + force/=3; //water absorbs 2/3 velocity + + if(self.flags&FL_MONSTER&&loser==world) + force/=2; + + if(self.frozen>0&&force>10) + force=10; + + if((force>=1&&loser.classname!="player")||force>=10) + { +/* dprint("Damage other ("); + dprint(loser.classname); + dprint("): "); + dprint(ftos(force)); + dprint("\n"); +*/ T_Damage (loser, self, self, force); + if(loser.health<=0) + {//Keep 75% of vel if broke loser apart + // dprint("Broke through\n"); + newmis=spawn(); + newmis.mangle=self.velocity*0.75; + newmis.think=fix_vel; + newmis.enemy=self; + thinktime newmis : HX_FRAME_TIME; + } + } + } + + if(self.classname!="monster_mezzoman"&&self.netname!="spider"&&self.beast_time=100+self.health&&self.classname!="player")||(magnitude>=700&&self.safe_time=time)//crouching on impact absorbs 1/2 the damage + magnitude/=2; + } + magnitude/=40; + magnitude=magnitude - force/2;//If damage other, subtract half of that damage off of own injury + if(dmMode==DM_SIEGE) + force*=3; + + if(magnitude>=1) + { +//FIXME: Put in a thingtype impact sound function +/* dprint("Damage self ("); + dprint(self.classname); + dprint("): "); + dprint(ftos(magnitude)); + dprint("\n"); +*/ +// if(self.classname=="player_sheep"&&self.flags&FL_ONGROUND&&self.velocity_z>-50) +// return; + T_Damage(self,world,world,magnitude); + } + } + + self.last_impact=time; + if(self.flags&FL_ONGROUND) + self.last_onground=time; + } +} + +void obj_push() +{//MG +vector pushdir,pushangle,fpv; +float ontop,pushed,inertia,force,walkforce; + + if(other.solid==SOLID_PHASE||other.movetype==MOVETYPE_FLYMISSILE||other.movetype==MOVETYPE_BOUNCEMISSILE) + return; + + if(self.classname=="barrel"&&pointcontents(self.origin)!=CONTENT_EMPTY&&(!self.spawnflags&BARREL_SINK)) + { + self.classname="barrel_floating"; + self.think=float; + self.nextthink=time; + } + + if(self.classname=="player_sheep"&&other.classname=="catapult") + { + self.spawnflags(+)1; //Sheep won't move once on catapult + self.speed=0; + } + + if(self.last_impact + 0.1<=time) + obj_fly_hurt(other); + +// if (other.classname != "player"&&!(other.flags&FL_MONSTER)&&(!other.flags&FL_PUSH)&&other.movetype!=MOVETYPE_PUSHPULL) +// return; + + if(other!=world&&other.absmin_z >= self.origin_z+self.maxs_z - 5&&other.velocity_z<1) + { + if(!other.frozen&& + ( + (!other.flags2&FL_ALIVE&&other.flags&FL_MONSTER)|| + (self.flags&FL_MONSTER&&self.model!="models/spider.mdl"&&self.model!="models/scorpion.mdl") + ) + ) + { + makevectors(other.angles); + v_forward_z=1; + other.velocity=v_forward*300; + other.flags(-)FL_ONGROUND; + } + if(other.flags&FL_CLIENT&&!other.frozen) + ontop = FALSE; + else + { + ontop=TRUE; +// other.flags(+)FL_ONGROUND; + } + } + + if(self.flags&FL_MONSTER) + { + if(other!=world&&self.absmin_z >= other.absmax_z - 3&&self.velocity_z<1&&other.movetype!=MOVETYPE_FLYMISSILE&&other.movetype!=MOVETYPE_BOUNCE&&other.movetype!=MOVETYPE_BOUNCEMISSILE) + self.flags(+)FL_ONGROUND; + if(self.frozen<=0&&!self.artifact_active&ARTFLAG_STONED) + return; + } + +// if(self.classname=="barrel"&&other.classname=="player") +// dprintv("Player hit me with vel: %s\n",other.velocity); + + if(!other.velocity) + return; + + if (self.impulse == 20) + return; + + if(!self.mass) + inertia=1; + if(self.mass<=30) + inertia=self.mass/3; + else + inertia=self.mass/33; + + if(other.strength) + force=vlen(other.velocity)*(other.strength/40+0.5); + else + force=vlen(other.velocity); + + if(pointcontents(self.origin)==CONTENT_WATER||pointcontents(self.origin)==CONTENT_SLIME||pointcontents(self.origin)==CONTENT_LAVA) + force/=3; + +//FIXME: mass should determine how fast the object can be pushed +// if (self.mass > 199*force) // Too heavy to move + if (self.mass >= 1000) // Too heavy to move + return; + +//So you can push frozen guys around before they melt + if(self.frozen>0) + { + self.freeze_time=time+10; + self.wait=time + 10; + } + + if(ontop) + return; + + walkforce=force/inertia/40;//20 is the frame time... + if(self.classname=="barrel"&&self.aflag) + {//on side + vector dir1, dir2; + float dot_forward,dot_right; + self.angles_z=0; + self.v_angle_x=self.v_angle_z=0; + makevectors(self.v_angle); + + if(ontop) + dir1=normalize(other.velocity); + else + dir1=normalize(self.origin-other.origin); + + dir2=normalize(v_forward); + dir1_z=dir2_z=0; + + dot_forward= dir1*dir2; + + self.enemy=other; + if(dot_forward>=0.9) + { + self.movedir=dir2;//test + self.movedir_z=0; + self.speed += force/inertia; + if(self.speed>other.strength*300) + self.speed=other.strength*300; + traceline(self.origin,self.origin+dir2*48,FALSE,self); + if(trace_fraction==1.0) + { + self.velocity=self.movedir*self.speed; + self.think=obj_barrel_roll; + self.nextthink=time; + } + } + else if(dot_forward<=-0.9) + { + self.movedir=dir2;//test + self.movedir_z=0; + self.speed += force/inertia*-1; + if(self.speed0.2) + { + if(dot_forward >0.1) + { + self.angles_y-=walkforce*10; + } + else if(dot_forward<-0.1) + { + self.angles_y+=walkforce*10; + } + } + else if(dot_right<-0.2) + { + if(dot_forward >0.1) + { + self.angles_y+=walkforce*10; + } + else if(dot_forward<-0.1) + { + self.angles_y-=walkforce*10; + } + } + self.v_angle_y=self.angles_y; + } + } + else + { + pushdir=normalize(other.velocity); + pushdir_z=0;//no push into ground or up + pushangle=vectoangles(pushdir); + + pushed=FALSE; + walkforce=force/inertia/10;//20 is the frame rate... work in frametime? +// if(self.classname=="barrel"&&other.classname=="player") +// dprintf("Push force = %s\n",walkforce); + if(!walkmove(pushangle_y,walkforce,FALSE))//FIXME: check mass + { + if(self.classname=="barrel")//trace_ent.classname=="catapult"&& + { + self.velocity=pushdir*100; + self.velocity_z=80;//EZ Lift + } + else + { + if(other.absmax_z<=self.origin_z+self.mins_z*0.75) + pushdir_z*=2; + fpv=(pushdir*force*2*(1/inertia)+self.velocity)*0.5; + self.velocity_x=fpv_x; + self.velocity_y=fpv_y; + } + if(self.flags&FL_ONGROUND) + { + if(self.velocity_z<0) + self.velocity_z=0; + self.flags-=FL_ONGROUND; + } + if(self.velocity!='0 0 0') + pushed=TRUE; + } + else + pushed=TRUE; + + if(pushed&&self.classname!="barrel_floating") + { + if(self.pain_finished<=time) + { + if(self.classname=="player_sheep") + { + if(random()<0.3) + sheep_sound(.75); + if(!infront(other)&&random()<0.5&&self.speed) +//FIXME- find current think and set transition to run + self.think=sheep_trot; + } + else if(self.thingtype==THINGTYPE_WOOD||self.thingtype==THINGTYPE_WOOD_METAL) + {//FIXME: make more net friendly + sound(self,CHAN_VOICE,"misc/pushwood.wav",1,ATTN_NORM); + self.pain_finished=time + 1.041; + } + else if ((self.thingtype==THINGTYPE_GREYSTONE) || (self.thingtype==THINGTYPE_BROWNSTONE)) + { + sound(self,CHAN_VOICE,"misc/pushston.wav",1,ATTN_NORM); + self.pain_finished=time + .711; + } + else if(self.thingtype==THINGTYPE_METAL) + { + sound(self,CHAN_VOICE,"misc/pushmetl.wav",1,ATTN_NORM); + self.pain_finished=time + .835; + } + } + } + } +} + + + +/*QUAKED obj_chair (0.3 0.1 0.6) (-10 -10 -5) (10 10 40) +A wooden chair. +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void obj_chair() +{ + precache_model("models/chair.mdl"); + + CreateEntityNew(self,ENT_CHAIR,"models/chair.mdl",chunk_death); + + self.touch = obj_push; + self.flags = self.flags | FL_PUSH; +} + + +/*QUAKED obj_barstool (0.3 0.1 0.6) (-10 -10 -5) (10 10 32) +A bar stool - Drinks on the house! +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void obj_barstool() +{ + precache_model3("models/stool.mdl"); + + CreateEntityNew(self,ENT_BARSTOOL,"models/stool.mdl",chunk_death); + + self.touch = obj_push; + self.flags = self.flags | FL_PUSH; +} + + +/*QUAKED obj_tree (0.3 0.1 0.6) (-42 -42 0) (42 42 160) +A tree that has no leaves +-------------------------FIELDS------------------------- +health : 1000 +-------------------------------------------------------- +*/ +void obj_tree() +{ + precache_model2("models/tree.mdl"); + CreateEntityNew(self,ENT_TREEDEAD,"models/tree.mdl",chunk_death); +} + +void tree2_death (void) +{ + self.owner.nextthink = time + .01; + self.owner.think = chunk_death; + chunk_death(); +} + +/*QUAKED obj_tree2 (0.3 0.1 0.6) (-140 -140 -16) (140 140 220) +A tree with a round top of leaves +-------------------------FIELDS------------------------- +health : 1000 +-------------------------------------------------------- +*/ +void obj_tree2() +{ + entity top; + + precache_model("models/tree2.mdl"); + CreateEntityNew(self,ENT_TREE,"models/tree2.mdl",tree2_death); + + top = spawn(); + top.scale = self.scale; + + CreateEntityNew(top,ENT_TREETOP,top.model,tree2_death); + + top.origin = self.origin; + + if (self.scale) // Move top according to scale + top.origin_z += top.scale * 104; + else + top.origin_z += 104; + + top.health = self.health; + top.classname = "tree2top"; + + top.owner = self; + self.owner = top; + +} + +/*QUAKED obj_bench (0.3 0.1 0.6) (-30 -30 0) (30 30 40) +A wooden bench +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void obj_bench() +{ + precache_model3("models/bench.mdl"); + CreateEntityNew(self,ENT_BENCH,"models/bench.mdl",chunk_death); + + self.touch = obj_push; +} + + +/*QUAKED obj_cart (0.3 0.1 0.6) (-36 -32 -10) (36 75 64) +A cart +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void obj_cart() +{ + precache_model("models/cart.mdl"); + CreateEntityNew(self,ENT_CART,"models/cart.mdl",chunk_death); + self.hull=HULL_SCORPION; + + self.touch = obj_push; + self.flags = self.flags | FL_PUSH; +} + + +/*QUAKED obj_chest1 (0.3 0.1 0.6) (-16 -16 0) (16 16 32) +A treasure chest +-------------------------FIELDS------------------------- +skin - 0 - generic texture (default) + 1 - roman texture +-------------------------------------------------------- +*/ +void obj_chest1() +{ + precache_model("models/chest1.mdl"); + CreateEntityNew(self,ENT_CHEST1,"models/chest1.mdl",chunk_death); + + self.touch = obj_push; + self.flags = self.flags | FL_PUSH; +} + + +/*QUAKED obj_chest2 (0.3 0.1 0.6) (-16 -16 0) (16 16 32) +A treasure chest on legs +-------------------------FIELDS------------------------- +skin - 0 - generic texture (default) + 1 - meso texture + 2 - egypt texture +-------------------------------------------------------- +*/ +void obj_chest2() +{ + precache_model3("models/chest2.mdl"); + CreateEntityNew(self,ENT_CHEST2,"models/chest2.mdl",chunk_death); + + self.touch = obj_push; + self.flags = self.flags | FL_PUSH; + +} + +/*QUAKED obj_chest3 (0.3 0.1 0.6) (-16 -16 0) (16 16 32) +A treasure chest on legs +-------------------------FIELDS------------------------- +none +-------------------------------------------------------- +*/ +void obj_chest3() +{ + precache_model2("models/chest3.mdl"); + CreateEntityNew(self,ENT_CHEST3,"models/chest3.mdl",chunk_death); + + self.touch = obj_push; + self.flags = self.flags | FL_PUSH; + +} +/* +void boulder_fall (void) +{ + if(!self.flags&FL_ONGROUND||self.frags=0) + self.velocity_z-=10; + } + + self.think=boulder_fall; + self.nextthink=time+0.1; +} + +void boulder_push() +{ + if(self.velocity) + self.avelocity=self.velocity*-1; + obj_fly_hurt(other); + if(other.movetype&&other.velocity!='0 0 0'&&other.solid!=SOLID_TRIGGER&&other.solid!=SOLID_PHASE&&other.solid) + { + if(!walkmove(other.angles_y,1,TRUE)) + { + dprint("can't walk\n"); + self.velocity=(other.velocity+self.velocity)*0.5; + self.frags=time+0.01; + } + if(self.flags&FL_ONGROUND) + { + self.movetype=MOVETYPE_BOUNCEMISSILE;//movetype_slide- no friction + self.flags-=FL_ONGROUND; + } + } +} +*/ +/*QUAK-ED obj_boulder (0.3 0.1 0.6) (-32 -32 -32) (32 32 32) +A big freaking rock +-------------------------FIELDS------------------------- +health = 75 +mass = 25 +-------------------------------------------------------- +*/ +/* +void obj_boulder (void) +{ + precache_model2("models/boulder.mdl"); + CreateEntityNew(self,ENT_BOULDER,"models/boulder.mdl",chunk_death); + + self.flags = self.flags | FL_PUSH; + self.touch = obj_push; + +// self.think=boulder_fall; +// self.nextthink=time+0.1; +} +*/ + +/*QUAKED obj_sword (0.3 0.1 0.6) (-16 -16 -8) (16 16 8) +A sword +-------------------------FIELDS------------------------- +health = 50 +-------------------------------------------------------- +*/ +void obj_sword (void) +{ + precache_model("models/sword.mdl"); + CreateEntityNew(self,ENT_SWORD,"models/sword.mdl",chunk_death); + + if(self.targetname) + self.use=chunk_death; +} + + +/* +void BalBoltStick (void) +{ +vector dir; + self.velocity='0 0 0'; + self.movetype=MOVETYPE_NONE; + self.solid=SOLID_BBOX; + self.takedamage=DAMAGE_YES; + if (!self.health) + self.health=10; + self.th_die=chunk_death; + makevectors(self.angles); + dir=normalize(v_forward); + if(pointcontents(self.origin+dir*24)!=CONTENT_SOLID) + remove(self); +} +*/ + +void BalBoltTouch (void) +{ + if(other.takedamage) + { + vector dir; +//FIXME: Skewer them + if(other!=self.goalentity&&self.velocity!='0 0 0') + { + self.goalentity=other; + dir=normalize(self.velocity); + traceline(self.origin-dir*25,self.origin+dir*25,FALSE,self); + if(other.thingtype==THINGTYPE_FLESH) + MeatChunks (trace_endpos,self.velocity*0.5+'0 0 200', 3,trace_ent); + SpawnPuff (trace_endpos, self.velocity*0.5+'0 0 200', self.dmg,trace_ent); +// if(other.health+20my_pitch_z) + { + if(ideal_pitch_z-my_pitch_z>self.count) + pitchmod=self.count; + else + pitchmod=ideal_pitch_z-my_pitch_z; + self.angles_z+=pitchmod; + } + else if(ideal_pitch_zself.count) + pitchmod=self.count; + else + pitchmod=my_pitch_z-ideal_pitch_z; + self.angles_z-=pitchmod; + } + if(self.last_attack+self.speedself.friction) + other.flags-=FL_ONGROUND; +} + +void ice_slab_melt (void) +{ + if(self.scale>0.05) + { + self.scale-=0.05; + setsize(self,self.mins*0.9,self.maxs*0.9); + thinktime self : 0.1; + } + else + remove(self); +} + +void obj_ice (void) +{ +//thingtype_ice, need ice chunks + if(self.flags2&FL_SUMMONED) + { +//Make pushable, floating?! + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_NONE; + self.drawflags(+)SCALE_TYPE_XYONLY; + self.scale = 1; + self.think = ice_slab_melt; + thinktime self : 10; + } + else + { + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + } + self.takedamage=DAMAGE_YES; + self.thingtype = THINGTYPE_ICE; + setorigin (self, self.origin); + setmodel (self, self.model); + + self.frozen=TRUE; + self.classname="ice"; + + self.use = chunk_death; + + self.drawflags+=MLS_ABSLIGHT; + + if(!self.abslight) + self.abslight = 0.75; + + if(!self.spawnflags&1) + self.drawflags+=DRF_TRANSLUCENT; + + if(!self.health) + self.health = 20; + self.max_health = self.health; + + if(!self.friction) + self.friction = 0.2; + +// self.touch = friction_change_touch; + self.touch = ice_touch; + self.th_die = chunk_death; +} + +/*QUAKED obj_beefslab (0.3 0.1 0.6) (-16 -16 0) (16 16 40) +A slab of beef. +-------------------------FIELDS------------------------- +health = 50 +-------------------------------------------------------- +*/ +void obj_beefslab (void) +{ + precache_model3("models/beefslab.mdl"); + CreateEntityNew(self,ENT_BEEFSLAB,"models/beefslab.mdl",chunk_death); +} + +/*QUAKED obj_seaweed (0.3 0.1 0.6) (-8 -8 0) (8 8 32) +An animate seaweed that sways from side to side. +-------------------------FIELDS------------------------- +health = 10 +-------------------------------------------------------- +*/ +void obj_seaweed (void) +{ + precache_model("models/seaweed.mdl"); + CreateEntityNew(self,ENT_SEAWEED,"models/seaweed.mdl",chunk_death); +} + +/*QUAKED obj_statue_lion (0.3 0.1 0.6) (-56 -14 0) (56 14 60) +Statue of a lion. +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- + +*/ +void obj_statue_lion(void) +{ + precache_model2("models/lion.mdl"); + CreateEntityNew(self,ENT_STATUE_LION,"models/lion.mdl",chunk_death); + + self.drawflags += SCALE_ORIGIN_BOTTOM; + +} + +/*QUAKED obj_statue_athena(0.3 0.1 0.6) (-30 -30 0) (30 30 90) +Statue of a Athena +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- + +*/ +void obj_statue_athena (void) +{ + precache_model2("models/athena.mdl"); + CreateEntityNew(self,ENT_STATUE_ATHENA,"models/athena.mdl",chunk_death); + + self.drawflags += SCALE_ORIGIN_BOTTOM; + +} + + +/*QUAKED obj_statue_neptune(0.3 0.1 0.6) (-30 -30 0) (30 30 100) +Statue of Neptune (I think) +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- + +*/ +void obj_statue_neptune (void) +{ + precache_model2("models/neptune.mdl"); + CreateEntityNew(self,ENT_STATUE_NEPTUNE,"models/neptune.mdl",chunk_death); + + self.drawflags += SCALE_ORIGIN_BOTTOM; + +} + +/*QUAKED obj_bonepile(0.3 0.1 0.6) (-10 -10 0) (10 10 10) +A pile of bones. Uses the model of the puzzle keep1 +-------------------------FIELDS------------------------- +health = +-------------------------------------------------------- +*/ +void obj_bonepile (void) +{ + precache_model3("models/bonepile.mdl"); + CreateEntityNew(self,ENT_BONEPILE,"models/bonepile.mdl",chunk_death); + + self.use = chunk_death; + + self.drawflags += SCALE_ORIGIN_BOTTOM; +} + +/*QUAKED obj_statue_caesar(0.3 0.1 0.6) (-24 -24 0) (24 24 90) +Statue of a Caesar Romero +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- +*/ +void obj_statue_caesar (void) +{ + precache_model2("models/caesar.mdl"); + CreateEntityNew(self,ENT_STATUE_CAESAR,"models/caesar.mdl",chunk_death); + + self.drawflags += SCALE_ORIGIN_BOTTOM; + +} + +/*QUAKED obj_statue_snake_coil (0.3 0.1 0.6) (-44 -44 0) (44 44 90) +Statue of a coiled snake (just like the one that comes to life) but this one doesn't come to life. +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- +*/ +void obj_statue_snake_coil (void) +{ + precache_model2 ("models/snake.mdl"); + CreateEntityNew(self,ENT_STATUE_SNAKE_COIL,"models/snake.mdl",chunk_death); + + self.scale = .5; + self.drawflags += SCALE_ORIGIN_BOTTOM; + +} + +/*QUAKED obj_skull (0.3 0.1 0.6) (-8 -8 0) (8 8 16) +A skull, suitable for over the fireplace or perhaps a colorful holiday display +-------------------------FIELDS------------------------- +health = 10 +-------------------------------------------------------- +*/ +void obj_skull (void) +{ + precache_model("models/skull.mdl"); + CreateEntityNew(self,ENT_SKULL,"models/skull.mdl",chunk_death); +} + +/*QUAKED obj_pew (0.3 0.1 0.6) (-16 -40 0) (16 40 50) +A church pew - like you might find in a church. +-------------------------FIELDS------------------------- +health = 50 +-------------------------------------------------------- +*/ +void obj_pew (void) +{ + precache_model("models/pew.mdl"); + CreateEntityNew(self,ENT_PEW,"models/pew.mdl",chunk_death); +} + +/*QUAKED obj_statue_olmec (0.3 0.1 0.6) (-40 -40 0) (40 40 130) +A olmec statue, of course. What the heck is an olmec? +-------------------------FIELDS------------------------- +health = 50 +-------------------------------------------------------- +*/ +void obj_statue_olmec (void) +{ + precache_model2("models/olmec1.mdl"); + CreateEntityNew(self,ENT_STATUE_OLMEC,"models/olmec1.mdl",chunk_death); +} + +/*QUAKED obj_statue_mars (0.3 0.1 0.6) (-30 -30 0) (30 30 80) +A statue of Mars. +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- +*/ +void obj_statue_mars (void) +{ + precache_model2("models/mars.mdl"); + CreateEntityNew(self,ENT_STATUE_MARS,"models/mars.mdl",chunk_death); +} + +/*QUAKED obj_playerhead_paladin (0.3 0.1 0.6) (-8 -8 0) (8 8 16) +The head of the paladin. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_playerhead_paladin (void) +{ + precache_model("models/h_pal.mdl"); + CreateEntityNew(self,ENT_PLAYERHEAD,"models/h_pal.mdl",chunk_death); + self.use=chunk_death; +} + +/*QUAKED obj_playerhead_assassin (0.3 0.1 0.6) (-8 -8 0) (8 8 16) +The head of the assassin. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_playerhead_assassin (void) +{ + precache_model("models/h_ass.mdl"); + CreateEntityNew(self,ENT_PLAYERHEAD,"models/h_ass.mdl",chunk_death); + self.use=chunk_death; +} + +/*QUAKED obj_playerhead_necromancer (0.3 0.1 0.6) (-8 -8 0) (8 8 16) +The head of the necromancer. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_playerhead_necromancer (void) +{ + precache_model("models/h_nec.mdl"); + CreateEntityNew(self,ENT_PLAYERHEAD,"models/h_nec.mdl",chunk_death); + self.use=chunk_death; +} + +/*QUAKED obj_playerhead_crusader (0.3 0.1 0.6) (-8 -8 0) (8 8 16) +The head of the crusader. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_playerhead_crusader (void) +{ + precache_model("models/h_cru.mdl"); + CreateEntityNew(self,ENT_PLAYERHEAD,"models/h_cru.mdl",chunk_death); + self.use=chunk_death; +} + +/*QUAKED obj_statue_king (0.3 0.1 0.6) (-30 -30 0) (30 30 120) +A statue of a king holding a sword in front of him. +-------------------------FIELDS------------------------- +health = 200 +-------------------------------------------------------- +*/ +void obj_statue_king (void) +{ + precache_model3("models/king.mdl"); + CreateEntityNew(self,ENT_STATUE_KING,"models/king.mdl",chunk_death); + self.mins -= '0 0 80'; + self.maxs -= '0 0 80'; + setsize(self, self.mins, self.maxs); +} + +/*QUAKED obj_plant_generic (0.3 0.1 0.6) (-10 -10 0) (10 10 20) +A generic plant that should have some kind of pot placed below it. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_plant_generic (void) +{ + precache_model("models/plantgen.mdl"); + CreateEntityNew(self,ENT_PLANT_GENERIC,"models/plantgen.mdl",chunk_death); +} + +/*QUAKED obj_plant_meso (0.3 0.1 0.6) (-10 -10 0) (10 10 40) +A generic plant that should have some kind of pot placed below it. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_plant_meso (void) +{ + precache_model2("models/plantmez.mdl"); + CreateEntityNew(self,ENT_PLANT_MESO,"models/plantmez.mdl",chunk_death); +} + +/*QUAKED obj_plant_rome (0.3 0.1 0.6) (-24 -24 0) (24 24 90) +A plant for the Rome area. +-------------------------FIELDS------------------------- +health = 20 +-------------------------------------------------------- +*/ +void obj_plant_rome (void) +{ + precache_model2("models/plantrom.mdl"); + CreateEntityNew(self,ENT_PLANT_ROME,"models/plantrom.mdl",chunk_death); +} + +/*QUAKED obj_skeleton_throne (0.3 0.1 0.6) (-33 -33 -0) (33 33 115) +*/ +void obj_skeleton_throne (void) +{ +entity sk_king,box2,box3; + precache_model("models/throne.mdl"); + precache_model("models/sk-throne.mdl"); + CreateEntityNew(self,ENT_SKELTHRN,"models/throne.mdl",SUB_Null); + self.drawflags(+)SCALE_ORIGIN_BOTTOM; + + sk_king=spawn(); + self.movechain=sk_king; + setmodel(sk_king,"models/sk-throne.mdl"); + setsize(sk_king,'0 0 0','0 0 0'); + setorigin(sk_king,self.origin); + sk_king.angles=self.angles; + sk_king.drawflags(+)SCALE_ORIGIN_BOTTOM; + if(self.abslight) + { + self.drawflags(+)MLS_ABSLIGHT; + sk_king.abslight=self.abslight; + sk_king.drawflags(+)MLS_ABSLIGHT; + } + + makevectors(self.angles); + box2=spawn(); + box2.solid=SOLID_BBOX; + setsize(box2,'-26 -26 0','26 26 36'); + setorigin(box2,self.origin-v_forward*7); + box3=spawn(); + box3.solid=SOLID_BBOX; + if(self.angles_y==0||self.angles_y==180) + setsize(box3,'-4 -30 0','4 30 115'); + else + setsize(box3,'-30 -4 0','30 4 115'); + setorigin(box3,self.origin-v_forward*29); +} + + +void let_go_excal () +{ +entity oself; + sound(other,CHAN_AUTO,"weapons/unsheath.wav",1,ATTN_NORM); + dprint(other.netname); + dprint(" is The Defender of the Crown!"); + centerprint_all_clients("The Defender of the Crown has been chosen!\n",other); + centerprint(other,"You have been chosen as Halcyon's succesor!@Excelsior is yours, go forth and smite@thine enemies righteously!"); + other.flags2(+)FL2_EXCALIBUR; + other.effects(+)EF_LIGHT; + other.health=other.max_health; + other.oldweapon = FALSE; + other.weapon = IT_WEAPON1; + oself=self; + self=other; + restore_weapon(); + PlayerSpeed_Calc(self); + + self=oself; + WriteByte (MSG_ALL, SVC_MIDI_NAME); + WriteString (MSG_ALL, "ofortuna"); + WriteTeam (SVC_ISDOC,other); + remove(self); +} + +void excal_reset () +{ + self.frame = 16; + self.nextthink = -1; +} + +void()excal_swing2 = [++39 .. 51] +{ + if(cycle_wrapped) + { + self.attack_finished=time+0.5; + self.think=excal_reset; + thinktime self : 0.05; + } + else + { + if(self.frame==43) + sound (self, CHAN_VOICE, "weapons/met2flsh.wav", 1, ATTN_NORM); + T_Damage(other,self,self,10); + } +}; + +void()excal_swing1 = [++17 .. 38] +{ + if(cycle_wrapped) + { + self.attack_finished=time+0.5; + self.think=excal_reset; + thinktime self : 0.05; + } + else + { + if(self.frame==23) + sound (self, CHAN_VOICE, "weapons/met2flsh.wav", 1, ATTN_NORM); + T_Damage(other,self,self,10); + } +}; + +void check_siege_team () +{ + if(self.attack_finished>time) + return; + + if(other.siege_team==ST_DEFENDER) + { + if(other.playerclass==CLASS_PALADIN) + let_go_excal(); + } + else + { + sound (self, CHAN_WEAPON, "weapons/vorpswng.wav", 1, ATTN_NORM); + if(random()<0.5) + excal_swing1(); + else + excal_swing2(); + } +} + +void wait_for_paladin () +{ + self.solid=SOLID_TRIGGER; + setsize(self,'-24 -24 0','24 24 64'); + self.touch = check_siege_team; +} + +void () bestow_excalibur = [++0 .. 16] +{ + if(self.frame==7) + starteffect(CE_RIPPLE, self.origin,'0 0 0',2);//splash sound + else if(random()<0.5) + starteffect(CE_RIPPLE, self.origin,'0 0 0',1);//no drip sound +//FIXME: water particles? splashing up? + if(self.frame==16) + { + self.effects=EF_BRIGHTLIGHT; + self.think=wait_for_paladin; + thinktime self : 0.1; + } +}; + +void ready_bestow_excalibur2 () +{ + centerprint_all_clients("Excelsior has Arisen!\n",world); + setmodel(self,"models/lakeswd.mdl"); + bestow_excalibur(); +} + +void ready_bestow_excalibur () +{ + if(activator.siege_team==ST_DEFENDER) + return;//so defenders can't give themselves Excalibur early + + if(self.fail_chance) + if(random(100) 100) + return; + + ldmg = (random() + random() + random()) * 4; + T_Damage (self.enemy, self, self, ldmg); + + if (side) + { + makevectors (self.angles); + if (side == 1) + SpawnMeatSpray (self.origin + v_forward*16, random(-100,100) * v_right); + else + SpawnMeatSpray (self.origin + v_forward*16, side * v_right); + } +}; + + +void() ogre_stand1 =[ $stand1, ogre_stand2 ] {ai_stand();}; +void() ogre_stand2 =[ $stand2, ogre_stand3 ] {ai_stand();}; +void() ogre_stand3 =[ $stand3, ogre_stand4 ] {ai_stand();}; +void() ogre_stand4 =[ $stand4, ogre_stand5 ] {ai_stand();}; +void() ogre_stand5 =[ $stand5, ogre_stand6 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "ogre/ogidle.wav", 1, ATTN_IDLE); +ai_stand(); +}; +void() ogre_stand6 =[ $stand6, ogre_stand7 ] {ai_stand();}; +void() ogre_stand7 =[ $stand7, ogre_stand8 ] {ai_stand();}; +void() ogre_stand8 =[ $stand8, ogre_stand9 ] {ai_stand();}; +void() ogre_stand9 =[ $stand9, ogre_stand1 ] {ai_stand();}; + +void() ogre_walk1 =[ $walk1, ogre_walk2 ] {ai_walk(3);}; +void() ogre_walk2 =[ $walk2, ogre_walk3 ] {ai_walk(2);}; +void() ogre_walk3 =[ $walk3, ogre_walk4 ] { +ai_walk(2); +if (random() < 0.2) + sound (self, CHAN_VOICE, "ogre/ogidle.wav", 1, ATTN_IDLE); +}; +void() ogre_walk4 =[ $walk4, ogre_walk5 ] {ai_walk(2);}; +void() ogre_walk5 =[ $walk5, ogre_walk6 ] {ai_walk(2);}; +void() ogre_walk6 =[ $walk6, ogre_walk7 ] { +ai_walk(5); +if (random() < 0.1) + sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE); +}; +void() ogre_walk7 =[ $walk7, ogre_walk8 ] {ai_walk(3);}; +void() ogre_walk8 =[ $walk8, ogre_walk9 ] {ai_walk(2);}; +void() ogre_walk9 =[ $walk9, ogre_walk10 ] {ai_walk(3);}; +void() ogre_walk10 =[ $walk10, ogre_walk11 ] {ai_walk(1);}; +void() ogre_walk11 =[ $walk11, ogre_walk12 ] {ai_walk(2);}; +void() ogre_walk12 =[ $walk12, ogre_walk13 ] {ai_walk(3);}; +void() ogre_walk13 =[ $walk13, ogre_walk14 ] {ai_walk(3);}; +void() ogre_walk14 =[ $walk14, ogre_walk15 ] {ai_walk(3);}; +void() ogre_walk15 =[ $walk15, ogre_walk16 ] {ai_walk(3);}; +void() ogre_walk16 =[ $walk16, ogre_walk1 ] {ai_walk(4);}; + +void() ogre_run1 =[ $run1, ogre_run2 ] {ai_run(9); +if (random() < 0.2) + sound (self, CHAN_VOICE, "ogre/ogidle2.wav", 1, ATTN_IDLE); +}; +void() ogre_run2 =[ $run2, ogre_run3 ] {ai_run(12);}; +void() ogre_run3 =[ $run3, ogre_run4 ] {ai_run(8);}; +void() ogre_run4 =[ $run4, ogre_run5 ] {ai_run(22);}; +void() ogre_run5 =[ $run5, ogre_run6 ] {ai_run(16);}; +void() ogre_run6 =[ $run6, ogre_run7 ] {ai_run(4);}; +void() ogre_run7 =[ $run7, ogre_run8 ] {ai_run(13);}; +void() ogre_run8 =[ $run8, ogre_run1 ] {ai_run(24);}; + +void() ogre_swing1 =[ $swing1, ogre_swing2 ] {ai_charge(11); +sound (self, CHAN_WEAPON, "ogre/ogsawatk.wav", 1, ATTN_NORM); +}; +void() ogre_swing2 =[ $swing2, ogre_swing3 ] {ai_charge(1);}; +void() ogre_swing3 =[ $swing3, ogre_swing4 ] {ai_charge(4);}; +void() ogre_swing4 =[ $swing4, ogre_swing5 ] {ai_charge(13);}; +void() ogre_swing5 =[ $swing5, ogre_swing6 ] {ai_charge(9); chainsaw(0);self.angles_y = self.angles_y + random()*25;}; +void() ogre_swing6 =[ $swing6, ogre_swing7 ] {chainsaw(200);self.angles_y = self.angles_y + random()* 25;}; +void() ogre_swing7 =[ $swing7, ogre_swing8 ] {chainsaw(0);self.angles_y = self.angles_y + random()* 25;}; +void() ogre_swing8 =[ $swing8, ogre_swing9 ] {chainsaw(0);self.angles_y = self.angles_y + random()* 25;}; +void() ogre_swing9 =[ $swing9, ogre_swing10 ] {chainsaw(0);self.angles_y = self.angles_y + random()* 25;}; +void() ogre_swing10 =[ $swing10, ogre_swing11 ] {chainsaw(-200);self.angles_y = self.angles_y + random()* 25;}; +void() ogre_swing11 =[ $swing11, ogre_swing12 ] {chainsaw(0);self.angles_y = self.angles_y + random()* 25;}; +void() ogre_swing12 =[ $swing12, ogre_swing13 ] {ai_charge(3);}; +void() ogre_swing13 =[ $swing13, ogre_swing14 ] {ai_charge(8);}; +void() ogre_swing14 =[ $swing14, ogre_run1 ] {ai_charge(9);}; + +void() ogre_smash1 =[ $smash1, ogre_smash2 ] {ai_charge(6); +sound (self, CHAN_WEAPON, "ogre/ogsawatk.wav", 1, ATTN_NORM); +}; +void() ogre_smash2 =[ $smash2, ogre_smash3 ] {ai_charge(0);}; +void() ogre_smash3 =[ $smash3, ogre_smash4 ] {ai_charge(0);}; +void() ogre_smash4 =[ $smash4, ogre_smash5 ] {ai_charge(1);}; +void() ogre_smash5 =[ $smash5, ogre_smash6 ] {ai_charge(4);}; +void() ogre_smash6 =[ $smash6, ogre_smash7 ] {ai_charge(4); chainsaw(0);}; +void() ogre_smash7 =[ $smash7, ogre_smash8 ] {ai_charge(4); chainsaw(0);}; +void() ogre_smash8 =[ $smash8, ogre_smash9 ] {ai_charge(10); chainsaw(0);}; +void() ogre_smash9 =[ $smash9, ogre_smash10 ] {ai_charge(13); chainsaw(0);}; +void() ogre_smash10 =[ $smash10, ogre_smash11 ] {chainsaw(1);}; +void() ogre_smash11 =[ $smash11, ogre_smash12 ] {ai_charge(2); chainsaw(0); +self.nextthink = self.nextthink + random()*0.2;}; // slight variation +void() ogre_smash12 =[ $smash12, ogre_smash13 ] {ai_charge();}; +void() ogre_smash13 =[ $smash13, ogre_smash14 ] {ai_charge(4);}; +void() ogre_smash14 =[ $smash14, ogre_run1 ] {ai_charge(12);}; + +void() ogre_nail1 =[ $shoot1, ogre_nail2 ] {ai_face();}; +void() ogre_nail2 =[ $shoot2, ogre_nail3 ] {ai_face();}; +void() ogre_nail3 =[ $shoot2, ogre_nail4 ] {ai_face();}; +void() ogre_nail4 =[ $shoot3, ogre_nail5 ] {ai_face();OgreFireGrenade();}; +void() ogre_nail5 =[ $shoot4, ogre_nail6 ] {ai_face();}; +void() ogre_nail6 =[ $shoot5, ogre_nail7 ] {ai_face();}; +void() ogre_nail7 =[ $shoot6, ogre_run1 ] {ai_face();}; + +void() ogre_pain1 =[ $pain1, ogre_pain2 ] {}; +void() ogre_pain2 =[ $pain2, ogre_pain3 ] {}; +void() ogre_pain3 =[ $pain3, ogre_pain4 ] {}; +void() ogre_pain4 =[ $pain4, ogre_pain5 ] {}; +void() ogre_pain5 =[ $pain5, ogre_run1 ] {}; + + +void() ogre_painb1 =[ $painb1, ogre_painb2 ] {}; +void() ogre_painb2 =[ $painb2, ogre_painb3 ] {}; +void() ogre_painb3 =[ $painb3, ogre_run1 ] {}; + + +void() ogre_painc1 =[ $painc1, ogre_painc2 ] {}; +void() ogre_painc2 =[ $painc2, ogre_painc3 ] {}; +void() ogre_painc3 =[ $painc3, ogre_painc4 ] {}; +void() ogre_painc4 =[ $painc4, ogre_painc5 ] {}; +void() ogre_painc5 =[ $painc5, ogre_painc6 ] {}; +void() ogre_painc6 =[ $painc6, ogre_run1 ] {}; + + +void() ogre_paind1 =[ $paind1, ogre_paind2 ] {}; +void() ogre_paind2 =[ $paind2, ogre_paind3 ] {ai_pain(10);}; +void() ogre_paind3 =[ $paind3, ogre_paind4 ] {ai_pain(9);}; +void() ogre_paind4 =[ $paind4, ogre_paind5 ] {ai_pain(4);}; +void() ogre_paind5 =[ $paind5, ogre_paind6 ] {}; +void() ogre_paind6 =[ $paind6, ogre_paind7 ] {}; +void() ogre_paind7 =[ $paind7, ogre_paind8 ] {}; +void() ogre_paind8 =[ $paind8, ogre_paind9 ] {}; +void() ogre_paind9 =[ $paind9, ogre_paind10 ] {}; +void() ogre_paind10=[ $paind10, ogre_paind11 ] {}; +void() ogre_paind11=[ $paind11, ogre_paind12 ] {}; +void() ogre_paind12=[ $paind12, ogre_paind13 ] {}; +void() ogre_paind13=[ $paind13, ogre_paind14 ] {}; +void() ogre_paind14=[ $paind14, ogre_paind15 ] {}; +void() ogre_paind15=[ $paind15, ogre_paind16 ] {}; +void() ogre_paind16=[ $paind16, ogre_run1 ] {}; + +void() ogre_paine1 =[ $paine1, ogre_paine2 ] {}; +void() ogre_paine2 =[ $paine2, ogre_paine3 ] {ai_pain(10);}; +void() ogre_paine3 =[ $paine3, ogre_paine4 ] {ai_pain(9);}; +void() ogre_paine4 =[ $paine4, ogre_paine5 ] {ai_pain(4);}; +void() ogre_paine5 =[ $paine5, ogre_paine6 ] {}; +void() ogre_paine6 =[ $paine6, ogre_paine7 ] {}; +void() ogre_paine7 =[ $paine7, ogre_paine8 ] {}; +void() ogre_paine8 =[ $paine8, ogre_paine9 ] {}; +void() ogre_paine9 =[ $paine9, ogre_paine10 ] {}; +void() ogre_paine10=[ $paine10, ogre_paine11 ] {}; +void() ogre_paine11=[ $paine11, ogre_paine12 ] {}; +void() ogre_paine12=[ $paine12, ogre_paine13 ] {}; +void() ogre_paine13=[ $paine13, ogre_paine14 ] {}; +void() ogre_paine14=[ $paine14, ogre_paine15 ] {}; +void() ogre_paine15=[ $paine15, ogre_run1 ] {}; + + +void(entity attacker, float damage) ogre_pain = +{ + local float r; + +// don't make multiple pain sounds right after each other + if (self.pain_finished > time) + return; + + sound (self, CHAN_VOICE, "ogre/ogpain1.wav", 1, ATTN_NORM); + + r = random(); + + if (r < 0.25) + { + ogre_pain1 (); + self.pain_finished = time + 1; + } + else if (r < 0.5) + { + ogre_painb1 (); + self.pain_finished = time + 1; + } + else if (r < 0.75) + { + ogre_painc1 (); + self.pain_finished = time + 1; + } + else if (r < 0.88) + { + ogre_paind1 (); + self.pain_finished = time + 2; + } + else + { + ogre_paine1 (); + self.pain_finished = time + 2; + } +}; + +void() ogre_die1 =[ $death1, ogre_die2 ] {}; +void() ogre_die2 =[ $death2, ogre_die3 ] {}; +void() ogre_die3 =[ $death3, ogre_die4 ] +{self.solid = SOLID_NOT; +self.ammo_rockets = 2;DropBackpack();}; +void() ogre_die4 =[ $death4, ogre_die5 ] {}; +void() ogre_die5 =[ $death5, ogre_die6 ] {}; +void() ogre_die6 =[ $death6, ogre_die7 ] {}; +void() ogre_die7 =[ $death7, ogre_die8 ] {}; +void() ogre_die8 =[ $death8, ogre_die9 ] {}; +void() ogre_die9 =[ $death9, ogre_die10 ] {}; +void() ogre_die10 =[ $death10, ogre_die11 ] {}; +void() ogre_die11 =[ $death11, ogre_die12 ] {}; +void() ogre_die12 =[ $death12, ogre_die13 ] {}; +void() ogre_die13 =[ $death13, ogre_die14 ] {}; +void() ogre_die14 =[ $death14, ogre_die14 ] {}; + +void() ogre_bdie1 =[ $bdeath1, ogre_bdie2 ] {}; +void() ogre_bdie2 =[ $bdeath2, ogre_bdie3 ] {ai_forward(5);}; +void() ogre_bdie3 =[ $bdeath3, ogre_bdie4 ] +{self.solid = SOLID_NOT; +self.ammo_rockets = 2;DropBackpack();}; +void() ogre_bdie4 =[ $bdeath4, ogre_bdie5 ] {ai_forward(1);}; +void() ogre_bdie5 =[ $bdeath5, ogre_bdie6 ] {ai_forward(3);}; +void() ogre_bdie6 =[ $bdeath6, ogre_bdie7 ] {ai_forward(7);}; +void() ogre_bdie7 =[ $bdeath7, ogre_bdie8 ] {ai_forward(25);}; +void() ogre_bdie8 =[ $bdeath8, ogre_bdie9 ] {}; +void() ogre_bdie9 =[ $bdeath9, ogre_bdie10 ] {}; +void() ogre_bdie10 =[ $bdeath10, ogre_bdie10 ] {}; + +void() ogre_die = +{ +// check for gib + if (self.health < -80) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("models/h_ogre.mdl", self.health); + ThrowGib ("models/gib3.mdl", self.health); + ThrowGib ("models/gib3.mdl", self.health); + ThrowGib ("models/gib3.mdl", self.health); + return; + } + + sound (self, CHAN_VOICE, "ogre/ogdth.wav", 1, ATTN_NORM); + + if (random() < 0.5) + ogre_die1 (); + else + ogre_bdie1 (); +}; + +void() ogre_melee = +{ + if (random() > 0.5) + ogre_smash1 (); + else + ogre_swing1 (); +}; + + +/*QUAK-ED monster_ogre (1 0 0) (-32 -32 -24) (32 32 64) Ambush + +*/ +void() monster_ogre = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("models/ogre.mdl"); + precache_model ("models/h_ogre.mdl"); + precache_model ("models/grenade.mdl"); + + precache_sound ("ogre/ogdrag.wav"); + precache_sound ("ogre/ogdth.wav"); + precache_sound ("ogre/ogidle.wav"); + precache_sound ("ogre/ogidle2.wav"); + precache_sound ("ogre/ogpain1.wav"); + precache_sound ("ogre/ogsawatk.wav"); + precache_sound ("ogre/ogwake.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "models/ogre.mdl"); + + setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); + self.health = 200; + + self.th_stand = ogre_stand1; + self.th_walk = ogre_walk1; + self.th_run = ogre_run1; + self.th_die = ogre_die; + self.th_melee = ogre_melee; + self.th_missile = ogre_nail1; + self.th_pain = ogre_pain; + + walkmonster_start(); +}; + +void() monster_ogre_marksman = +{ + monster_ogre (); +}; + diff --git a/oldone.hc b/oldone.hc new file mode 100644 index 0000000..9c0470a --- /dev/null +++ b/oldone.hc @@ -0,0 +1,286 @@ +/* + * $Header: /HexenWorld/Siege/Oldone.hc 3 5/25/98 1:39p Mgummelt $ + */ +/* +============================================================================== + +OLD ONE + +============================================================================== +*/ +$cd id1/models/old_one +$origin 0 0 24 +$base base +$skin skin +$scale 1 + +void() finale_1; +void() finale_2; +void() finale_3; +void() finale_4; + + +entity shub; + +$frame old1 old2 old3 old4 old5 old6 old7 old8 old9 +$frame old10 old11 old12 old13 old14 old15 old16 old17 old18 old19 +$frame old20 old21 old22 old23 old24 old25 old26 old27 old28 old29 +$frame old30 old31 old32 old33 old34 old35 old36 old37 old38 old39 +$frame old40 old41 old42 old43 old44 old45 old46 + +$frame shake1 shake2 shake3 shake4 shake5 shake6 shake7 shake8 +$frame shake9 shake10 shake11 shake12 shake12 shake13 shake14 +$frame shake15 shake16 shake17 shake18 shake19 shake20 + +//void() old_stand =[ $old1, old_stand ] {}; + +void() old_idle1 =[ $old1, old_idle2 ] {}; +void() old_idle2 =[ $old2, old_idle3 ] {}; +void() old_idle3 =[ $old3, old_idle4 ] {}; +void() old_idle4 =[ $old4, old_idle5 ] {}; +void() old_idle5 =[ $old5, old_idle6 ] {}; +void() old_idle6 =[ $old6, old_idle7 ] {}; +void() old_idle7 =[ $old7, old_idle8 ] {}; +void() old_idle8 =[ $old8, old_idle9 ] {}; +void() old_idle9 =[ $old9, old_idle10 ] {}; +void() old_idle10 =[ $old10, old_idle11 ] {}; +void() old_idle11 =[ $old11, old_idle12 ] {}; +void() old_idle12 =[ $old12, old_idle13 ] {}; +void() old_idle13 =[ $old13, old_idle14 ] {}; +void() old_idle14 =[ $old14, old_idle15 ] {}; +void() old_idle15 =[ $old15, old_idle16 ] {}; +void() old_idle16 =[ $old16, old_idle17 ] {}; +void() old_idle17 =[ $old17, old_idle18 ] {}; +void() old_idle18 =[ $old18, old_idle19 ] {}; +void() old_idle19 =[ $old19, old_idle20 ] {}; +void() old_idle20 =[ $old20, old_idle21 ] {}; +void() old_idle21 =[ $old21, old_idle22 ] {}; +void() old_idle22 =[ $old22, old_idle23 ] {}; +void() old_idle23 =[ $old23, old_idle24 ] {}; +void() old_idle24 =[ $old24, old_idle25 ] {}; +void() old_idle25 =[ $old25, old_idle26 ] {}; +void() old_idle26 =[ $old26, old_idle27 ] {}; +void() old_idle27 =[ $old27, old_idle28 ] {}; +void() old_idle28 =[ $old28, old_idle29 ] {}; +void() old_idle29 =[ $old29, old_idle30 ] {}; +void() old_idle30 =[ $old30, old_idle31 ] {}; +void() old_idle31 =[ $old31, old_idle32 ] {}; +void() old_idle32 =[ $old32, old_idle33 ] {}; +void() old_idle33 =[ $old33, old_idle34 ] {}; +void() old_idle34 =[ $old34, old_idle35 ] {}; +void() old_idle35 =[ $old35, old_idle36 ] {}; +void() old_idle36 =[ $old36, old_idle37 ] {}; +void() old_idle37 =[ $old37, old_idle38 ] {}; +void() old_idle38 =[ $old38, old_idle39 ] {}; +void() old_idle39 =[ $old39, old_idle40 ] {}; +void() old_idle40 =[ $old40, old_idle41 ] {}; +void() old_idle41 =[ $old41, old_idle42 ] {}; +void() old_idle42 =[ $old42, old_idle43 ] {}; +void() old_idle43 =[ $old43, old_idle44 ] {}; +void() old_idle44 =[ $old44, old_idle45 ] {}; +void() old_idle45 =[ $old45, old_idle46 ] {}; +void() old_idle46 =[ $old46, old_idle1 ] {}; + + +void() old_thrash1 =[ $shake1, old_thrash2 ] {lightstyle(0, "m");}; +void() old_thrash2 =[ $shake2, old_thrash3 ] {lightstyle(0, "k");}; +void() old_thrash3 =[ $shake3, old_thrash4 ] {lightstyle(0, "k");}; +void() old_thrash4 =[ $shake4, old_thrash5 ] {lightstyle(0, "i");}; +void() old_thrash5 =[ $shake5, old_thrash6 ] {lightstyle(0, "g");}; +void() old_thrash6 =[ $shake6, old_thrash7 ] {lightstyle(0, "e");}; +void() old_thrash7 =[ $shake7, old_thrash8 ] {lightstyle(0, "c");}; +void() old_thrash8 =[ $shake8, old_thrash9 ] {lightstyle(0, "a");}; +void() old_thrash9 =[ $shake9, old_thrash10 ] {lightstyle(0, "c");}; +void() old_thrash10 =[ $shake10, old_thrash11 ] {lightstyle(0, "e");}; +void() old_thrash11 =[ $shake11, old_thrash12 ] {lightstyle(0, "g");}; +void() old_thrash12 =[ $shake12, old_thrash13 ] {lightstyle(0, "i");}; +void() old_thrash13 =[ $shake13, old_thrash14 ] {lightstyle(0, "k");}; +void() old_thrash14 =[ $shake14, old_thrash15 ] {lightstyle(0, "m");}; +void() old_thrash15 =[ $shake15, old_thrash16 ] {lightstyle(0, "m"); +self.cnt = self.cnt + 1; +if (self.cnt != 3) + self.think = old_thrash1; +}; +void() old_thrash16 =[ $shake16, old_thrash17 ] {lightstyle(0, "g");}; +void() old_thrash17 =[ $shake17, old_thrash18 ] {lightstyle(0, "c");}; +void() old_thrash18 =[ $shake18, old_thrash19 ] {lightstyle(0, "b");}; +void() old_thrash19 =[ $shake19, old_thrash20 ] {lightstyle(0, "a");}; +void() old_thrash20 =[ $shake20, old_thrash20 ] {finale_4();}; + +//============================================================================ + +void() finale_1 = +{ + local entity pos, pl; + local entity timer; + + intermission_exittime = time + 10000000; // never allow exit + intermission_running = 1; + + // find the intermission spot + pos = find (world, classname, "info_intermission"); + if (!pos) + error ("no info_intermission"); + pl = find (world, classname, "misc_teleporttrain"); + if (!pl) + error ("no teleporttrain"); + remove (pl); + + WriteByte (MSG_ALL, SVC_FINALE); + WriteString (MSG_ALL, ""); + + pl = find (world, classname, "player"); + while (pl != world) + { + pl.view_ofs = '0 0 0'; + pl.angles = other.v_angle = pos.mangle; + pl.fixangle = TRUE; // turn this way immediately + pl.map = self.map; + pl.nextthink = time + 0.5; + pl.takedamage = DAMAGE_NO; + pl.solid = SOLID_NOT; + pl.movetype = MOVETYPE_NONE; + pl.modelindex = 0; + setorigin (pl, pos.origin); + pl = find (pl, classname, "player"); + } + + // make fake versions of all players as standins, and move the real + // players to the intermission spot + + // wait for 1 second + timer = spawn(); + timer.nextthink = time + 1; + timer.think = finale_2; +}; + +void() finale_2 = +{ + local vector o; + + // start a teleport splash inside shub + + o = shub.origin - '0 100 0'; + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_TELEPORT); + WriteCoord (MSG_BROADCAST, o_x); + WriteCoord (MSG_BROADCAST, o_y); + WriteCoord (MSG_BROADCAST, o_z); + + sound (shub, CHAN_VOICE, "misc/r_tele1.wav", 1, ATTN_NORM); + + self.nextthink = time + 2; + self.think = finale_3; +}; + +void() finale_3 = +{ + // start shub thrashing wildly + shub.think = old_thrash1; + sound (shub, CHAN_VOICE, "boss2/death.wav", 1, ATTN_NORM); + lightstyle(0, "abcdefghijklmlkjihgfedcb"); +}; + +void() finale_4 = +{ + // throw tons of meat chunks + local vector oldo; + local float x, y, z; + local float r; + local entity n; + + sound (self, CHAN_VOICE, "boss2/pop2.wav", 1, ATTN_NORM); + + oldo = self.origin; + + z = 16; + while (z <= 144) + { + x = -64; + while (x <= 64) + { + y = -64; + while (y <= 64) + { + self.origin_x = oldo_x + x; + self.origin_y = oldo_y + y; + self.origin_z = oldo_z + z; + + r = random(); + if (r < 0.3) + ThrowGib ("progs/gib1.mdl", -999); + else if (r < 0.6) + ThrowGib ("progs/gib2.mdl", -999); + else + ThrowGib ("progs/gib3.mdl", -999); + y = y + 32; + } + x = x + 32; + } + z = z + 96; + } + // start the end text + WriteByte (MSG_ALL, SVC_FINALE); + WriteString (MSG_ALL, "Congratulations and well done! You have\nbeaten the hideous Shub-Niggurath, and\nher hundreds of ugly changelings and\nmonsters. You have proven that your\nskill and your cunning are greater than\nall the powers of Quake. You are the\nmaster now. Id Software salutes you."); + +// put a player model down + n = spawn(); + setmodel (n, "progs/player.mdl"); + oldo = oldo - '32 264 0'; + setorigin (n, oldo); + n.angles = '0 290 0'; + n.frame = 1; + + remove (self); + +// switch cd track + WriteByte (MSG_ALL, SVC_CDTRACK); + WriteByte (MSG_ALL, 3); + WriteByte (MSG_ALL, 3); + lightstyle(0, "m"); +}; + +//============================================================================ + +void () nopain = +{ + self.health = 40000; +}; + +//============================================================================ + + +/*QUAK-ED monster_oldone (1 0 0) (-16 -16 -24) (16 16 32) +*/ +void() monster_oldone = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model2 ("progs/oldone.mdl"); + + precache_sound2 ("boss2/death.wav"); + precache_sound2 ("boss2/idle.wav"); + precache_sound2 ("boss2/sight.wav"); + precache_sound2 ("boss2/pop2.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/oldone.mdl"); + setsize (self, '-160 -128 -24', '160 128 256'); + + self.health = 40000; // kill by telefrag + self.think = old_idle1; + self.nextthink = time + 0.1; + self.takedamage = DAMAGE_YES; + self.th_pain = nopain; + self.th_die = finale_1; + shub = self; + + total_monsters = total_monsters + 1; +}; + diff --git a/paladin.hc b/paladin.hc new file mode 100644 index 0000000..db243c3 --- /dev/null +++ b/paladin.hc @@ -0,0 +1,434 @@ +/* + * $Header: /HexenWorld/Siege/paladin.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\players\paladin\newfinal\paladin.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\players\paladin\newfinal +$origin 0 0 0 +$base BASE skin +$skin skin +$skin SKIN2 +$skin skin3 +$flags 0 + +// +$frame attgnt1 attgnt2 attgnt3 attgnt4 attgnt5 +$frame attgnt6 attgnt7 attgnt8 attgnt9 attgnt10 +$frame attgnt11 + +// +$frame attstf1 attstf2 attstf3 attstf4 + +// +$frame attswd1 attswd2 attswd3 attswd4 attswd5 +$frame attswd6 attswd7 attswd8 attswd9 attswd10 +$frame attswd11 attswd12 + +// +$frame crouch1 crouch2 crouch3 crouch4 crouch5 +$frame crouch6 crouch7 crouch8 crouch9 crouch10 +$frame crouch11 crouch12 crouch13 crouch14 crouch15 +$frame crouch16 crouch17 crouch18 crouch19 crouch20 + +// +$frame death1 death2 death3 death4 death5 +$frame death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 +$frame death16 death17 death18 death19 death20 + +// +$frame decap1 decap2 decap3 decap4 decap5 +$frame decap6 decap7 decap8 decap9 decap10 +$frame decap11 decap12 decap13 decap14 decap15 +$frame decap16 decap17 decap18 decap19 decap20 +$frame decap21 decap22 decap23 decap24 decap25 +$frame decap26 decap27 decap28 + +// +$frame flygnt1 flygnt2 flygnt3 flygnt4 flygnt5 +$frame flygnt6 flygnt7 flygnt8 flygnt9 flygnt10 +$frame flygnt11 flygnt12 flygnt13 flygnt14 flygnt15 + +// +$frame flystf1 flystf2 flystf3 flystf4 flystf5 +$frame flystf6 flystf7 flystf8 flystf9 flystf10 +$frame flystf11 flystf12 flystf13 flystf14 flystf15 + +// +$frame flyswd1 flyswd2 flyswd3 flyswd4 flyswd5 +$frame flyswd6 flyswd7 flyswd8 flyswd9 flyswd10 +$frame flyswd11 flyswd12 flyswd13 flyswd14 flyswd15 + +// +$frame jump1 jump2 jump3 jump4 jump5 +$frame jump6 jump7 jump8 jump9 jump10 +$frame jump11 jump12 + +// +$frame paingnt1 paingnt2 paingnt3 paingnt4 paingnt5 +$frame paingnt6 paingnt7 + +// +$frame painstf1 painstf2 painstf3 painstf4 painstf5 +$frame painstf6 painstf7 + +// +$frame painswd1 painswd2 painswd3 painswd4 painswd5 +$frame painswd6 painswd7 + +// +$frame rungnt1 rungnt2 rungnt3 rungnt4 rungnt5 +$frame rungnt6 rungnt7 rungnt8 rungnt9 rungnt10 +$frame rungnt11 rungnt12 + +// +$frame runstf1 runstf2 runstf3 runstf4 runstf5 +$frame runstf6 runstf7 runstf8 runstf9 runstf10 +$frame runstf11 runstf12 + +// +$frame runswd1 runswd2 runswd3 runswd4 runswd5 +$frame runswd6 runswd7 runswd8 runswd9 runswd10 +$frame runswd11 runswd12 + +// +$frame stdgnt1 stdgnt2 stdgnt3 stdgnt4 stdgnt5 +$frame stdgnt6 stdgnt7 stdgnt8 stdgnt9 stdgnt10 +$frame stdgnt11 stdgnt12 stdgnt13 + +// +$frame stdstf1 stdstf2 stdstf3 stdstf4 stdstf5 +$frame stdstf6 stdstf7 stdstf8 stdstf9 stdstf10 +$frame stdstf11 stdstf12 stdstf13 + +// +$frame stdswd1 stdswd2 stdswd3 stdswd4 stdswd5 +$frame stdswd6 stdswd7 stdswd8 stdswd9 stdswd10 +$frame stdswd11 stdswd12 stdswd13 + + + + +/*-------------------------- +ACTUAL (UNIQUE TO CLASS) PLAYER CODE +----------------------------*/ +void() player_paladin_run; +void() player_paladin_crouch_stand; +void() player_paladin_crouch_move; +void() player_paladin_stand; + +void() player_paladin_jump=[++$jump1..$jump12] +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_paladin_swim = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel<3) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_paladin_gauntlet_swim =[++$flygnt1..$flygnt15] +{ + player_paladin_swim(); +}; + +void() player_paladin_staff_swim =[++$flystf1..$flystf15] +{ + player_paladin_swim(); +}; + +void() player_paladin_swaxe_swim =[++$flyswd1..$flyswd15] +{ + player_paladin_swim(); +}; + +void() player_paladin_fly = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype!=MOVETYPE_FLY) + if (self.velocity_x || self.velocity_y) + self.think=self.th_run; + else + self.think=self.th_stand; +}; + +void() player_paladin_gauntlet_fly =[++$flygnt1..$flygnt15] +{ + player_paladin_fly(); +}; + +void() player_paladin_staff_fly =[++$flystf1..$flystf15] +{ + player_paladin_fly(); +}; + +void() player_paladin_swaxe_fly =[++$flyswd1..$flyswd15] +{ + player_paladin_fly(); +}; + +void() player_paladin_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_paladin_crouch_stand; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (self.velocity_x || self.velocity_y) + self.think=self.th_run; +}; + +void() player_paladin_gauntlet_stand =[++$stdgnt1..$stdgnt13] +{ + player_paladin_stand(); +}; + +void() player_paladin_staff_stand =[++$stdstf1..$stdstf13] +{ + player_paladin_stand(); +}; + +void() player_paladin_swaxe_stand =[++$stdswd1..$stdswd13] +{ + player_paladin_stand(); +}; + +void() player_paladin_run = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.hull==HULL_CROUCH) + self.think=player_paladin_crouch_move; + else if(self.waterlevel>2) + self.think=self.th_swim; + else if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if (!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; +}; + +void() player_paladin_gauntlet_run =[++$rungnt1..$rungnt12] +{ + player_paladin_run(); +}; + +void() player_paladin_staff_run =[++$runstf1..$runstf12] +{ + player_paladin_run(); +}; + +void() player_paladin_swaxe_run =[++$runswd1..$runswd12] +{ + player_paladin_run(); +}; + +void() player_paladin_crouch_stand = +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.frame>$crouch20 || self.frame<$crouch1) + self.frame=$crouch1; + if(self.movetype==MOVETYPE_FLY) + self.think=self.th_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_stand; + else if (self.velocity_x || self.velocity_y) + self.think=player_paladin_crouch_move; + thinktime self : HX_FRAME_TIME; +}; + +void() player_paladin_crouch_move =[++$crouch1..$crouch20] +{ + if(self.viewentity==self) + self.th_weapon(); + if(self.movetype==MOVETYPE_FLY) + self.think=player_paladin_fly; + else if(self.hull==HULL_PLAYER) + self.think=self.th_run; + else if (!self.velocity_x && !self.velocity_y) + self.think=player_paladin_crouch_stand; +}; + +void() player_paladin_attack= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped&&!self.button0) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_paladin_gauntlet_attack=[++$attgnt1..$attgnt11] +{ + player_paladin_attack(); +}; + +void() player_paladin_swaxe_attack=[++$attswd1..$attswd12] +{ + player_paladin_attack(); +}; + +void() player_paladin_staff_attack=[++$attstf1..$attstf4] +{ + player_paladin_attack(); +}; + +void() player_paladin_pain= +{ + if(self.viewentity==self) + self.th_weapon(); + if(cycle_wrapped) + { + if(!self.velocity_x && !self.velocity_y) + self.think=self.th_stand; + else + self.think=self.th_run; + } +}; + +void() player_paladin_gauntlet_pain =[++$paingnt1..$paingnt7] +{ + if(self.frame==$paingnt1) + PainSound(); + player_paladin_pain(); +}; + +void() player_paladin_staff_pain =[++$painstf1..$painstf7] +{ + if(self.frame==$painstf1) + PainSound(); + player_paladin_pain(); +}; + +void() player_paladin_swaxe_pain =[++$painswd1..$painswd7] +{ + if(self.frame==$painswd1) + PainSound(); + player_paladin_pain(); +}; + +void() player_paladin_die1=[++$death1..$death20] +{ + if(cycle_wrapped) + { + self.frame=$death20; + self.think=PlayerDead; + } +}; + +void() player_paladin_die2=[++$death1..$death20] +{ + if(cycle_wrapped) + { + self.frame=$death20; + self.think=PlayerDead; + } +}; + +void() player_paladin_behead = +{ + self.level=$decap1; + self.dmg=$decap28; + self.cnt=0; + player_behead(); +}; + +void Pal_Change_Weapon (void) +{ + if(self.weapon==IT_WEAPON1) + { + self.th_stand=player_paladin_gauntlet_stand; + self.th_missile=pal_gauntlet_fire; + self.th_run=player_paladin_gauntlet_run; + self.th_pain=player_paladin_gauntlet_pain; + self.th_swim=player_paladin_gauntlet_swim; + self.th_fly=player_paladin_gauntlet_fly; + } + else if(self.weapon==IT_WEAPON4) + { + self.th_stand=player_paladin_staff_stand; + self.th_missile=pal_purifier_fire; + self.th_run=player_paladin_staff_run; + self.th_pain=player_paladin_staff_pain; + self.th_swim=player_paladin_staff_swim; + self.th_fly=player_paladin_staff_fly; + } + else + { + self.th_stand=player_paladin_swaxe_stand; + if(self.weapon==IT_WEAPON2) + self.th_missile=pal_vorpal_fire; + else + self.th_missile=pal_axe_fire; + self.th_run=player_paladin_swaxe_run; + self.th_pain=player_paladin_swaxe_pain; + self.th_swim=player_paladin_swaxe_swim; + self.th_fly=player_paladin_swaxe_fly; + } + if(self.hull!=HULL_CROUCH) + self.think=self.th_stand; +} + +/* +void paladin_spurt () +{ + SpawnPuff (self.origin+'0 0 56', '0 0 35',5,self); + thinktime self : 0.1; +} +*/ +/*QUAK-ED paladin_dead (1 0 0) (-16 -16 0) (16 16 56) +*/ +/* +void paladin_dead(void) +{ + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.takedamage=DAMAGE_YES; + self.flags2(+)FL_ALIVE; + self.thingtype=THINGTYPE_FLESH; + self.frame=$decap14; + setmodel (self, "models/paladin.mdl"); + + setsize (self, '-16 -16 0', '16 16 200'); + self.hull=HULL_POINT; + self.health = self.max_health=2000; + self.mass = 2000; + self.drawflags(+)MLS_ABSLIGHT; + self.abslight=0.5; + self.think=paladin_spurt; + thinktime self : 0.1; +} +*/ + diff --git a/path.hc b/path.hc new file mode 100644 index 0000000..3ff94c0 --- /dev/null +++ b/path.hc @@ -0,0 +1,84 @@ +/* + * $Header: /HexenWorld/Siege/path.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +============= +pathcorner_touch + +Something has bumped into a path_corner. If it is a monster +change to the next target and continue. +============== +*/ +void() pathcorner_touch = +{ +local entity temp; + + if (other.pathentity != self) // This corner was not targeted by this monster + return; + + if (other.enemy) + return; // fighting, not following a path + + if(self.wait==-2&&other.flags&FL_MONSTER) + remove(other); + + temp = self; + self = other; + other = temp; + + self.goalentity = self.pathentity = find (world, targetname, other.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.pathentity) + { + self.pausetime = time + 999999; + self.th_stand (); + return; + } +}; + +/* +============================================================================== + +TARGET CODE + +The angle of the pathentity effects standing and bowing direction, but has no effect on movement, which always heads to the next target. + +targetname +must be present. The name of this pathentity. + +target +the next spot to move to. If not present, stop here for good. + +pausetime +The number of seconds to spend standing or bowing for path_stand or path_bow + +============================================================================== +*/ +float SYNCH = 1; +/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8) SYNCH +Monsters will continue walking towards the next target corner. + +FOR TRAINS: +-------------------------FIELDS------------------------- +SYNCH - Will make the train automatically calculate a new anglespeed based on the distance it's going and will finish the turn at the same time the move is done. +"speed" - how fast the train should move to this path corner. This will change the train's default speed to whatever you specify. Nice for trains that should speed up and slow down. No speed will let the train move at whatever speed it was last set to. +"angles" - how much to modify the train's angles by. So if you set it at '0 90 0', and the train was at an angle of '30 60 90', the train would rotate unitl it's angles equalled '30 150 90' +"anglespeed" - how fast the train should rotate to the new angle. Again, this will change the train's default anglespeed. +The defaults of all of these are 0. +-------------------------------------------------------- + +As usual, any rotating brush needs an origin brush. +*/ +void path_corner () +{ + if (!self.targetname) + objerror ("path_corner has no targetname"); + + if(!self.mangle) + self.mangle=self.angles; + self.solid = SOLID_TRIGGER; + self.touch = pathcorner_touch; + setsize (self, '-8 -8 -8', '8 8 8'); +} + diff --git a/plaque.hc b/plaque.hc new file mode 100644 index 0000000..37de209 --- /dev/null +++ b/plaque.hc @@ -0,0 +1,97 @@ +/* + * $Header: /HexenWorld/Siege/plaque.hc 3 5/25/98 1:39p Mgummelt $ + */ + +float PLAQUE_INVISIBLE = 1; +float PLAQUE_ACTIVATE = 2; + +/* +================ +plague_use + +Activate a plaque +================ +*/ +void plaque_use (void) +{ + if (self.spawnflags & PLAQUE_ACTIVATE) + self.inactive = 0; +} + +void plaque_touch (void) +{ + vector spot1, spot2; + + if (self.inactive) + return; + + if ((other.classname == "player") && (!other.plaqueflg)) + { + makevectors (other.v_angle); + spot1 = other.origin + other.view_ofs; + spot2 = spot1 + (v_forward*25); // Look just a little ahead + traceline (spot1, spot2 , FALSE, other); + + if ((trace_fraction == 1.0) || (trace_ent.classname!="plaque")) + { + traceline (spot1, spot2 - (v_up * 30), FALSE, other); // 30 down + + if ((trace_fraction == 1.0) || (trace_ent.classname!="plaque")) + { + traceline (spot1, spot2 + v_up * 30, FALSE, other); // 30 up + + if ((trace_fraction == 1.0) || (trace_ent.classname!="plaque")) + return; + } + } + + other.plaqueflg = 1; + other.plaqueangle = other.v_angle; + msg_entity = other; + plaque_draw(MSG_ONE,self.message); + + if (other.noise1 != "") + sound (other, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + else + sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + } +} + +/*QUAKED plaque (.5 .5 .5) ? INVISIBLE deactivated + +A plaque on the wall a player can read +-------------------------FIELDS------------------------- + +"message" the index of the string in the text file + +"noise1" the wav file activated when plaque is used + +deactivated - if this is on, the plaque will not be readable until a trigger has activated it. +-------------------------------------------------------- +*/ +void() plaque = +{ + setsize (self, self.mins, self.maxs); + setorigin (self, self.origin); + setmodel (self, self.model); + self.solid = SOLID_SLIDEBOX; + + if (deathmatch) // I don't do a remove because they might be a part of the architecture + return; + + self.use = plaque_use; + + precache_sound("raven/use_plaq.wav"); + self.noise = "raven/use_plaq.wav"; + + self.touch = plaque_touch; + + if (self.spawnflags & PLAQUE_INVISIBLE) + self.effects (+) EF_NODRAW; + + if (self.spawnflags & PLAQUE_ACTIVATE) + self.inactive = 1; + else + self.inactive = 0; +}; + diff --git a/plats.hc b/plats.hc new file mode 100644 index 0000000..1207279 --- /dev/null +++ b/plats.hc @@ -0,0 +1,1124 @@ +/* + * $Header: /HexenWorld/Siege/PLATS.hc 6 5/25/98 1:39p Mgummelt $ + */ +void()func_train_mp; +void() newplat_center_touch; +void() newplat_go_up; +void() newplat_go_down; +void() plat_center_touch; +void() plat_outside_touch; +void() plat_trigger_use; +void() plat_go_up; +void() plat_go_down; +void() plat_crush; +float PLAT_LOW_TRIGGER = 1; + +void() crusher_hit_bottom; +void() crusher_hit_top; +void() crusher_trigger_use; +void() crusher_go_up; +void() crusher_go_down; +float CRUSH_MULT = 1; +float CRUSH_SLIDE = 2; +float CRUSH_START_OPEN = 4; +float CRUSH_ENDPOS = 8; + +float START_BOTTOM = 1; +float START_RTRN= 2; +float CONTINUE= 4; + +void() train_wait; +float TRAIN_GLOW = 1; +float TRAIN_WAITTRIG = 2; +float TRAIN_RETURN = 4; + +void() plat_spawn_inside_trigger = +{ + local entity trigger; + local vector tmin, tmax; + + //middle trigger + + trigger = spawn(); + + if (self.classname == "newplat") + trigger.touch = newplat_center_touch; + else + trigger.touch = plat_center_touch; + + trigger.movetype = MOVETYPE_NONE; + trigger.solid = SOLID_TRIGGER; + trigger.enemy = self; + + tmin = self.mins + '25 25 0'; + tmax = self.maxs - '25 25 -8'; + tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8); + if (self.spawnflags & PLAT_LOW_TRIGGER) + tmax_z = tmin_z + 8; + + if (self.size_x <= 50) + { + tmin_x = (self.mins_x + self.maxs_x) / 2; + tmax_x = tmin_x + 1; + } + if (self.size_y <= 50) + { + tmin_y = (self.mins_y + self.maxs_y) / 2; + tmax_y = tmin_y + 1; + } + + setsize (trigger, tmin, tmax); +}; + +void() plat_hit_top = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.state = STATE_TOP; + self.think = plat_go_down; + self.nextthink = self.ltime + 3; +}; + +void() plat_hit_bottom = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.state = STATE_BOTTOM; +}; + +void() plat_go_down = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + self.state = STATE_DOWN; + SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom); +}; + +void() plat_go_up = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + self.state = STATE_UP; + SUB_CalcMove (self.pos1, self.speed, plat_hit_top); +}; + +void() plat_center_touch = +{ + if (other.classname != "player"&&other.movetype!=MOVETYPE_PUSHPULL)//Monsters too? + return; + + if (other.health <= 0) + return; + + self = self.enemy; + if (self.state == STATE_BOTTOM) + plat_go_up (); + else if (self.state == STATE_TOP) + self.nextthink = self.ltime + 1; // delay going down +}; + +void() plat_outside_touch = +{ + if (other.classname != "player"&&other.movetype!=MOVETYPE_PUSHPULL) + return; + + if (other.health <= 0) + return; + +//dprint ("plat_outside_touch\n"); + self = self.enemy; + if (self.state == STATE_TOP) + plat_go_down (); +}; + +void() plat_trigger_use = +{ + if (self.think) + return; // allready activated + plat_go_down(); +}; + +void() plat_crush = +{ + + T_Damage (other, self, self, 1); + + if (self.state == STATE_UP) + plat_go_down (); + else if (self.state == STATE_DOWN) + plat_go_up (); + else + objerror ("plat_crush: bad self.state\n"); +}; + +void() plat_use = +{ + self.use = SUB_Null; + if (self.state != STATE_UP) + objerror ("plat_use: not in up state"); + plat_go_down(); +}; + + +/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER +speed default 150 + +Plats are always drawn in the extended position, so they will light correctly. + +If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat. + +If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height. +Set "soundtype" to one of the following: +1) pulley +2) chain +*/ + +void() func_plat = +{ + + if (!self.t_length) + self.t_length = 80; + if (!self.t_width) + self.t_width = 10; + + if (self.soundtype == 0) + self.soundtype = 2; +// FIX THIS TO LOAD A GENERIC PLAT SOUND + + if (self.soundtype == 1) + { + precache_sound ("plats/pulyplt1.wav"); + precache_sound ("plats/pulyplt2.wav"); + self.noise = "plats/pulyplt1.wav"; + self.noise1 = "plats/pulyplt2.wav"; + } + + if (self.soundtype == 2) + { + precache_sound ("plats/chainplt1.wav"); + precache_sound ("plats/chainplt2.wav"); + self.noise = "plats/chainplt1.wav"; + self.noise1 = "plats/chainplt2.wav"; + } + + + self.mangle = self.angles; + self.angles = '0 0 0'; + + self.classname = "plat"; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + + self.blocked = plat_crush; + if (!self.speed) + self.speed = 150; + +// pos1 is the top position, pos2 is the bottom + self.pos1 = self.origin; + self.pos2 = self.origin; + if (self.height) + self.pos2_z = self.origin_z - self.height; + else + self.pos2_z = self.origin_z - self.size_z + 8; + + self.use = plat_trigger_use; + + plat_spawn_inside_trigger (); // the "start moving" trigger + + if (self.targetname) + { + self.state = STATE_UP; + self.use = plat_use; + } + else + { + setorigin (self, self.pos2); + self.state = STATE_BOTTOM; + } +}; + +//============================================================================ + +void() train_next; +void() func_train_find; + +void() train_blocked = +{ + if (time < self.attack_finished) return; + self.attack_finished = time + 0.5; + T_Damage (other, self, self, self.dmg); +}; + +void() train_use = +{ + if(self.wait==-1) + self.use=SUB_Null; + + if (self.spawnflags & TRAIN_GLOW) + { + self.effects (+) EF_BRIGHTLIGHT; + } + + if (self.decap != 1) + { + self.decap = 1; + if (self.think != train_next) + { + self.think = func_train_find; + train_next(); + } + } + else + { + if (self.spawnflags & TRAIN_RETURN) self.decap = 0; + else self.decap = 2; + } +}; + +void() train_wait = +{ + //Check to make sure train is active + if(self.decap!=2) + { + self.think = train_next; + if(self.wait==-2) + { + if(self.th_die) + { + if(self.pausetime) + { + self.think=self.th_die; + self.nextthink=self.ltime+self.pausetime; + } + else + { + self.th_die(); + return; + } + } + else + { + if(self.pausetime) + { + self.think=chunk_death; + self.nextthink=self.ltime+self.pausetime; + } + else + { + chunk_death(); + return; + } + } + } + else if(self.wait==-1) + self.nextthink=-1; + else if (self.wait) + { + self.nextthink = self.ltime + self.wait; + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + } + else self.nextthink = self.ltime + 0.1; + } + if (self.decap == 0 || self.decap == 2) + self.effects (-) EF_BRIGHTLIGHT; +}; + +void() train_rotate = +{ + local entity targ; + local vector dir; + + targ = self.enemy; + + if (targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0) + { + dir = self.angles; + dir += targ.mangle; + + SUB_CalcAngleMove (dir, self.speed, train_wait); + } + else + train_wait(); +}; + +void() train_next = +{ + local entity targ; + local vector dir; + float targ_speed, targ_aspeed; + + + targ = find (world, targetname, self.target); + self.target = targ.target; + + if (!self.decap && self.spawnflags & TRAIN_RETURN) + if (self.netname == targ.targetname) + self.decap = 2; + + if (!self.target) + objerror ("train_next: no next target"); + if (targ.wait) + self.wait = targ.wait; + else + self.wait = 0; + + self.enemy = targ; + + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + + if (targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0) + { + dir = self.angles; + dir += targ.mangle; + + if(targ.speed) + targ_speed=targ.speed; + else + targ_speed = self.speed; + + if(targ.anglespeed) + targ_aspeed=targ.anglespeed; + else + targ_aspeed = self.anglespeed; + + if(targ.spawnflags&SYNCH) + SUB_CalcMoveAndAngleInit (targ.origin - self.mins, targ_speed, dir, targ_aspeed, train_wait,TRUE); + else + SUB_CalcMoveAndAngleInit (targ.origin - self.mins, targ_speed, dir, targ_aspeed, train_wait,FALSE); + + } + else + SUB_CalcMove (targ.origin - self.mins, self.speed, train_rotate); + + if (self.spawnflags & TRAIN_WAITTRIG) + self.decap = 2; +}; + +void() func_train_find = +{ + local entity targ; + + targ = find (world, targetname, self.target); + self.target = targ.target; + setorigin (self, targ.origin - self.mins); + if (!self.targetname) + { // not triggered, so start immediately + self.decap = 1; + self.nextthink = self.ltime + 0.1; + self.think = train_next; + } +}; + +/*QUAKED func_train (0 .5 .8) ? GLOW TOGGLE RETURN TRANSLUCENT +Trains are moving platforms that players can ride. +The targets origin specifies the min point of the train at each corner. +The train spawns at the first target it is pointing at. +If the train is the target of a button or trigger, it will not begin moving until activated. +speed default 100 +dmg default 2 +soundtype +1) ratchet metal + +if train is only moving to one spot +"angle" - to tell it's direction +"distance" - in pixels, how far to move +"speed" - how fast it moves between spots (default=100) +"anglespeed" - how fast it rotates to a new angle (default = 100) +"wait" - -1 will make it stop forever, -2 will make it blow up (you can put the waits on the pathcorners and it will take the wait from there. +"pausetime" - How long to wait after getting to the end of it's path before blowing up, default is 0 +NOTE: If you give it a wait of -2, be sure to set the thingtype. +thingtype - type of chunks and sprites it will generate + 0 - glass + 1 - grey stone (default for trains) + 2 - wood + 3 - metal + 4 - flesh + 5 - fire + 6 - clay + 7 - leaves + 8 - hay + 9 - brown stone + 10 - cloth + 11 - wood & leaf + 12 - wood & metal + 13 - wood stone + 14 - metal stone + 15 - metal cloth + +The train will modify it's angles by whatever angles it's next path point has, so if it heads towards a path corner with an angle of '0 90 0', the train will rotate '0 90 0' on it's way to the pathpoint. If you make the anglespeed the same as the angle, the turn should finish right as the train gets to the new spot. + +NOTE: A path_corner using spawnflag "SYNCH" will make the train automatically calculate a new anglespeed based on the distance it's going and will finish the turn at the same time the move is done. + +As usual, any rotating brush needs an origin brush. + +"abslight" - to set the absolute light level + +if TRAIN_GLOW is checked, changes to a light globe sprite and lights up an area +*/ +void() func_train = +{ + local entity targ; + + if(world.spawnflags&MISSIONPACK) + { + func_train_mp(); + return; + } + + self.decap = 0; + + if (self.spawnflags & TRAIN_GLOW) { + self.solid = SOLID_NOT; + setmodel (self, "models/s_light.spr"); + } + else + { + self.solid = SOLID_BSP; + setmodel (self, self.model); + } + + if (!self.speed) self.speed = 100; + + if (!self.anglespeed) self.anglespeed = 100; + + if (!self.target) objerror ("func_train without a target"); + + if (!self.dmg) self.dmg = 2; + + if (self.soundtype == 1) + { + self.noise = ("plats/train2.wav"); + precache_sound ("plats/train2.wav"); + self.noise1 = ("plats/train1.wav"); + precache_sound ("plats/train1.wav"); + } + else + { + self.noise = self.noise1 = "misc/null.wav"; + precache_sound ("misc/null.wav"); + } + + if(self.wait==-2) + { + if(!self.thingtype) + self.thingtype=1; + if(!self.th_die) + self.th_die=chunk_death; + } + + self.cnt = 1; + self.movetype = MOVETYPE_PUSH; + self.blocked = train_blocked; + self.use = train_use; + self.classname = "train"; + + setsize (self, self.mins , self.maxs); + setorigin (self, self.origin); + + targ = find(world, target, self.target); + self.netname = targ.target; + + if (self.abslight) + self.drawflags(+)MLS_ABSLIGHT; + if (self.spawnflags & 8) + { + self.drawflags(+)DRF_TRANSLUCENT; + self.solid = SOLID_NOT; + } + + +// start trains on the second frame, to make sure their targets have had +// a chance to spawn + self.nextthink = self.ltime + 0.1; + self.think = func_train_find; +}; + +/*QUAK-ED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8) +This is used for the final bos +*/ +/* +void() misc_teleporttrain = +{ + if (!self.speed) + self.speed = 100; + if (!self.target) + objerror ("func_train without a target"); + + self.cnt = 1; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_PUSH; + self.blocked = train_blocked; + self.use = train_use; + self.avelocity = '100 200 300'; + + self.noise = ("misc/null.wav"); + precache_sound ("misc/null.wav"); + self.noise1 = ("misc/null.wav"); + precache_sound ("misc/null.wav"); + + precache_model2 ("models/teleport.mdl"); + setmodel (self, "models/teleport.mdl"); + setsize (self, self.mins , self.maxs); + setorigin (self, self.origin); + +// start trains on the second frame, to make sure their targets have had +// a chance to spawn + self.nextthink = self.ltime + 0.1; + self.think = func_train_find; +}; +*/ + +void() newplat_hit_bottom = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.state = STATE_BOTTOM; + self.lifetime = time + self.wait; + if (((self.spawnflags & START_RTRN) && !(self.spawnflags & START_BOTTOM)) || + (self.spawnflags & CONTINUE)) + { + self.nextthink = self.ltime + self.wait; + self.think=newplat_go_up; + } + setorigin (self.enemy, self.origin); +}; + +void() newplat_hit_top = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.state = STATE_TOP; + self.lifetime = time + self.wait; + + if (((self.spawnflags & START_RTRN) && (self.spawnflags & START_BOTTOM)) || + (self.spawnflags & CONTINUE)) + { + self.nextthink = self.ltime + self.wait; + self.think=newplat_go_down; + } + + setorigin (self.enemy, self.origin); +}; + +void() newplat_trigger_use = +{ + if (self.think) + return; // already activated + + if ((self.state==STATE_MOVING) || (self.lifetime > time)) + return; + + if (self.state == STATE_BOTTOM) + newplat_go_up (); + else + newplat_go_down (); +}; + + + +void() newplat_calc_down = +{ + self.state=STATE_MOVING; + SUB_CalcMove (self.pos2, self.speed, newplat_hit_bottom); +}; + +void() newplat_go_down = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + newplat_calc_down(); +}; + +void() newplat_calc_up = +{ + self.state=STATE_MOVING; + SUB_CalcMove (self.pos1, self.speed, newplat_hit_top); +}; + +void() newplat_go_up = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + newplat_calc_up(); +}; + +void() newplat_crush = +{ + T_Damage (other, self, self, 1); + if (self.velocity_z < 0) + newplat_calc_down (); + else if (self.velocity_z > 0) + newplat_calc_up(); + else + objerror ("newplat_crush: bad self.state\n"); +}; + +void() newplat_center_touch = +{ + + if ((other.classname != "player"&&other.movetype!=MOVETYPE_PUSHPULL) || (other.health <= 0)) + return; + + self = self.enemy; + if ((self.state==STATE_MOVING) || (self.lifetime > time)) + return; + + if (self.state == STATE_BOTTOM) + newplat_go_up (); + else + newplat_go_down (); +}; + +void() newplat_spawn_inside_trigger = +{ + local entity trigger; + + //middle trigger + trigger = spawn(); + + trigger.touch = newplat_center_touch; + + trigger.movetype = MOVETYPE_PUSH; + trigger.solid = SOLID_TRIGGER; + trigger.enemy = self; + self.enemy = trigger; + + setsize (trigger, self.mins,self.maxs); +}; + +/*QUAKED func_newplat (0 .5 .8) ? START_BOTTOM STRT_RTRN CONTINUE +speed default 150 + +If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height. + +Set "soundtype" to one of the following: +1) base fast +2) chain slow + +START_BOTTOM - where plat starts at +if checked plat starts at the bottom of it's movement + +START_RTRN - if check will return plat to start position. + +CONTINUE - plat will never stop moving + + +height - distance plat moves up or down + +wait - amount of time plat waits before moving (default 3) + + +*/ +void() func_newplat = +{ + + if (!self.t_length) + self.t_length = 80; + if (!self.t_width) + self.t_width = 10; + + if (self.soundtype == 0) + self.soundtype = 2; + + if (self.soundtype == 1) + { + precache_sound ("plats/pulyplt1.wav"); + precache_sound ("plats/pulyplt2.wav"); + self.noise = "plats/pulyplt1.wav"; + self.noise1 = "plats/pulyplt2.wav"; + } + + if (self.soundtype == 2) + { + precache_sound ("plats/chainplt1.wav"); + precache_sound ("plats/chainplt2.wav"); + self.noise = "plats/chainplt1.wav"; + self.noise1 = "plats/chainplt2.wav"; + } + + + + self.mangle = self.angles; + self.angles = '0 0 0'; + + self.classname = "newplat"; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + + if (!self.speed) + self.speed = 150; + + if (!self.wait) + self.wait = 3; + +// pos1 is the top position, pos2 is the bottom + self.pos1 = self.origin; + self.pos2 = self.origin; + + if (self.spawnflags & START_BOTTOM) + self.state=STATE_BOTTOM; + else + self.state=STATE_TOP; + + if (self.state==STATE_BOTTOM) + { + self.pos1_z = self.origin_z + self.height; + self.pos2_z = self.origin_z; + } + else + { + self.pos1_z = self.origin_z; + self.pos2_z = self.origin_z - self.height; + } + + self.use = newplat_trigger_use; + self.blocked = newplat_crush; + + newplat_spawn_inside_trigger (); //set the "start moving" trigger + +}; + + +/* +=============================================================================== + +FUNC_CRUSHER + +=============================================================================== +*/ + +void() crusher_slide_next = +{ + local vector vdestdelta; + local float len, tspeed; + + tspeed = self.speed; + + if (!tspeed) objerror("No speed defined!"); + + //Make sure we're not already at the destination + if (self.finaldest == self.origin) + { + self.velocity = '0 0 0'; + + if (self.state == STATE_DOWN) self.think = crusher_hit_bottom; + else if (self.state == STATE_UP) self.think = crusher_hit_top; + + self.nextthink = self.ltime + 0.1; + + return; + } + + //Set destdelta to the vector needed to move + vdestdelta = self.finaldest - self.origin; + + //Get the length of the vector + len = vlen (vdestdelta); + + //If the length is this small, just stop + if (len < 1) + { + if (self.state == STATE_DOWN) crusher_hit_bottom(); + else if (self.state == STATE_UP) crusher_hit_top(); + else dprint("NO STATE\n"); + return; + } + + self.nextthink = self.ltime + 0.1; + self.think = crusher_slide_next; + + self.velocity = vdestdelta * ((len / (len / 3)) / (self.speed / 100)); +}; + +void(vector tdest) crusher_slide = +{ + self.finaldest = tdest; + crusher_slide_next(); +}; + +void() crusher_hit_top = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.state = STATE_TOP; + + if (self.spawnflags & CRUSH_MULT) + return; + + if (!self.level) + { + self.think = crusher_go_down; + self.nextthink = self.ltime + 1; + } + else + self.nextthink = -1; +}; + +void() crusher_hit_bottom = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_NORM); + self.state = STATE_BOTTOM; + if (self.level && self.spawnflags & CRUSH_ENDPOS) return; + self.think = crusher_go_up; + self.nextthink = self.ltime + 1; +}; + +void() crusher_go_down = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + self.state = STATE_DOWN; + if (self.spawnflags & CRUSH_SLIDE) crusher_slide(self.pos2); + else SUB_CalcMove (self.pos2, self.speed, crusher_hit_bottom); +}; + +void() crusher_go_up = +{ + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_LOOP); + self.state = STATE_UP; + if (self.spawnflags & CRUSH_SLIDE) crusher_slide(self.pos1); + else SUB_CalcMove (self.pos1, self.speed, crusher_hit_top); +}; + +void() crusher_trigger_use = +{ + if (!self.level) + self.level = TRUE; + else + self.level = FALSE; + +//HCC doesn't like these together in one statement + if (self.think) + if (self.spawnflags & CRUSH_MULT) + return; // already activated + + crusher_go_down(); +}; + +void() crusher_crush = +{ + //Crusher does not return like a plat, it just keeps on crushin' + T_Damage (other, self, self, self.dmg); +}; + +void() crusher_use = +{ + if (!self.level) + self.level = TRUE; + else + self.level = FALSE; + + crusher_go_down(); +}; + +/*QUAKED func_crusher (0 .5 .8) ? multiple slide start_open end_open +speed default 150 +dmg default 10 + +If not targetname is given, crushers will start working immediatly + +Crushers are always drawn in the extended position, so they will light correctly. + +start_open = start in open position +multiple = go once, return, and wait to be triggered again +slide = slide move (like doors) +end_open = stop in the position opposite what they were drawn in + +"lip" same as doors +"speed" speed of the crusher +"wait pause until going in the other direction +"targetname" if set, no trigger is needed (use with multiple) +"dmg" damage the crusher does to a victim + +Set "soundtype" to one of the following: +1) base fast +2) chain slow +3) Guillotine +*/ + +void() func_crusher = +{ + SetMovedir(); + + if (self.soundtype == 0) self.soundtype = 2; + + if (self.soundtype == 1) + { + precache_sound ("plats/plat1.wav"); + precache_sound ("plats/plat2.wav"); + self.noise = "plats/plat1.wav"; + self.noise1 = "plats/plat2.wav"; + } + else if (self.soundtype == 2) + { + precache_sound ("plats/medplat1.wav"); + precache_sound ("plats/medplat2.wav"); + self.noise = "plats/medplat1.wav"; + self.noise1 = "plats/medplat2.wav"; + } + else if (self.soundtype == 3) + { + precache_sound3 ("plats/guiltin1.wav"); + precache_sound3 ("plats/guiltin2.wav"); + self.noise = "plats/guiltin1.wav"; + self.noise1 = "plats/guiltin2.wav"; + } + + self.mangle = self.angles; + self.angles = '0 0 0'; + + self.classname = "crusher"; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + + self.level = TRUE; + + if (!self.dmg) self.dmg = 10; + + self.blocked = crusher_crush; + + if (!self.speed) self.speed = 150; + + self.pos1 = self.origin; + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + + if (self.spawnflags & CRUSH_START_OPEN) + { + setorigin (self, self.pos2); + self.pos2 = self.pos1; + self.pos1 = self.origin; + } + + self.use = crusher_trigger_use; + + if (self.targetname) + { + self.state = STATE_UP; + self.use = crusher_use; + } + else + { + setorigin (self, self.pos2); + self.state = STATE_BOTTOM; + self.nextthink = self.ltime + 0.1; + self.think = crusher_use; + } +}; + +void reset_solid (void) +{ + +} + +void rot_mov_dmg (void) +{ + if(other==world) + return; + + if(other.classname=="player") + { + self.solid=SOLID_TRIGGER; + self.think=reset_solid; + thinktime self : 0.1; + } + + if(other.takedamage) + { + if(self.noise1) + sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,self.noise1,1,ATTN_NORM); + self.pain_finished=time+self.wait; + T_Damage(other,self,self.owner,self.dmg); + } +} + +void rot_mov_snd (void) +{ + if(self.pain_finished<=time) + { + sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,self.noise,1,ATTN_LOOP); + self.pain_finished=time+self.wait; + } + self.think=rot_mov_snd; + thinktime self : self.wait; +} + +void rot_mov_activate (void) +{ + if(self.dmg) + self.touch=rot_mov_dmg; + + if(!self.avelocity) + self.avelocity=self.o_angle; + + if(self.noise) + if(!self.wait) + objerror ("func_rotating_movechain: sound, but no delay time"); + else + { + self.think=rot_mov_snd; + thinktime self : 0; + } +} + +float NOANGLECHAIN = 1; + +/*QUAKED func_rotating_movechain (0 .5 .8) ? NOANGLECHAIN + +Only one other object in the world should have the same netname. If not, it will find and use only the first one it finds! + +If you're making multiple sawblades, for instance, label the mover and the rotater "sawblade1" for the first one, "sawblade2" for the second, and so on. + +If you give it a targetname, it will wait to be activated, this can be seperate from the object it's attached to. + +It will not do damage until it's been activated. + +NOANGLECHAIN = Setting this flag will stop it from modifying it's angles by the owner's angles, but will still movechain. +dmg = How much damage it should do when it touches. +noise = Noise it should make, if any, be sure to set the wait time +noise1 = noise it should make when it hits something +wait = Length of the sound so it knows when to loop it. +avelocity = The direction and speed it should spin: pitch yaw roll (this is relative to it's own axis, not the world) +netname = the name of the object it's linked to, that object must have a matching netname!!! + + +Needs something to tell it to stop? + +A way to make it die at the end of a path or if triggered again? + +Maybe make movechain_angle optional spawnflag? + +What do YOU think? We'd like to know... +*/ +void func_rotating_movechain (void) +{ + if(!self.netname) + objerror ("func_rotating_movechain has no netname"); + + self.owner=find(world,netname,self.netname); + if(self.owner.classname=="world") + objerror ("func_rotating_movechain has no owner!"); + + self.solid=SOLID_TRIGGER; + self.movetype=MOVETYPE_NOCLIP; + + setmodel(self,self.model); + setsize(self,self.mins,self.maxs); + setorigin(self,self.origin); + //dprint(vtos(self.avelocity)); + + self.owner.movechain=self; + if(!self.spawnflags&NOANGLECHAIN) + self.flags+=FL_MOVECHAIN_ANGLE; + + if(self.targetname) + { + self.use=rot_mov_activate; + self.o_angle=self.avelocity; + self.avelocity='0 0 0'; + } + else + { + self.think=rot_mov_activate; + thinktime self : 3;//wait a few secs for board to start + } +} + diff --git a/plats_mp.hc b/plats_mp.hc new file mode 100644 index 0000000..02980b6 --- /dev/null +++ b/plats_mp.hc @@ -0,0 +1,633 @@ +float SLOPE = 16; //Trains- follow angle for vec between path_corners +float ANGLEMATCH = 32; +float USE_ORIGIN = 64; +float ANGLE_WAIT = 128; +void() train_next_mp; +void() func_train_find_mp; +void rider_die(){} + +void() train_blocked_mp = +{ +// dprint("train blocked\n"); + if (time < self.attack_finished) return; + self.attack_finished = time + 0.5; + + if(self.dmg==-1&&self.anglespeed>0) + { + float on_top,in_front,to_right,other_dist; + vector avel, other_dir, throw_dir; + avel = normalize(self.avelocity); + makevectors(self.angles); + other_dir = normalize(other.origin-self.origin); + other_dist = vlen(other.origin - self.origin); + if(v_forward*other_dir>0)//in front + in_front=TRUE; + if(v_right*other_dir>0)//to right + to_right=TRUE; + if(v_up*other_dir>0)//on top + on_top=TRUE; + + if(avel_x>0)//pitch + if(on_top) + throw_dir_z+=self.anglespeed; + else + throw_dir_z+=self.anglespeed*-1; + if(avel_y>0)//yaw + if(in_front) + throw_dir+=v_right*self.anglespeed; + else + throw_dir+=v_right*self.anglespeed*-1; + if(avel_z>0)//roll + if(!to_right) + throw_dir_z+=self.anglespeed; + else + throw_dir_z+=self.anglespeed*-1; + + other.velocity=throw_dir; + other.flags(-)FL_ONGROUND; + } + else + T_Damage (other, self, self, self.dmg); +}; + +void() train_use_mp = +{ + if(self.movechain.model=="models/soulskul.mdl") + {//Hack to make Jeremy happy + self.weaponmodel=""; + self.movechain.think=rider_die; + thinktime self.movechain : 0.1; + } + + if(self.wait==-1) + self.use=SUB_Null; + + if (self.spawnflags & TRAIN_GLOW) + { + self.effects = EF_BRIGHTLIGHT; + } + + if (self.decap != 1) + { //Moving? + self.decap = 1; + if (self.think != train_next_mp) + { +// dprintf("Train wait %s first used by",self.wait); +// dprint(other.classname); +// dprint("\n"); + self.think = func_train_find_mp; + train_next_mp(); + } + } + else + { + if (self.spawnflags & TRAIN_RETURN) + self.decap = 0; + else + { +// dprintf("Train wait %s used whilst moving by",self.wait); +// dprint(other.classname); +// dprint("\n"); + self.decap = 2; + } + } +}; + +void() train_wait_mp = +{ + //Check to make sure train is active + //dprintf("wait func- my wait is :%s\n",self.wait); + + if(self.decap!=2) + { + //dprint("Train not 2 decap\n"); + self.think = train_next_mp; + if(self.wait==-2) + { + //dprint("Train breaking\n"); + stopSound(self,CHAN_UPDATE); + //sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, "misc/null.wav", 1, ATTN_NONE); + //dprint("Train wait of -2\n"); + if(self.th_die) + { + if(self.pausetime) + { + self.think=self.th_die; + self.nextthink=self.ltime+self.pausetime; + } + else + { + self.th_die(); + return; + } + } + else + { + if(self.pausetime) + { + self.think=chunk_death; + self.nextthink=self.ltime+self.pausetime; + } + else + { + chunk_death(); + return; + } + } + } + else if(self.wait==-1||self.wait==-3) + { + //dprint("Train wait of -1 or -3\n"); + if(self.level) + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_NORM); + else + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_NORM); + self.nextthink=-1; + } + else if (self.wait) + { + if(self.level) + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_NONE); + else + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_NORM); + self.nextthink = self.ltime + self.wait; + //dprintf("Next think: %s\n",self.nextthink); + //dprintf("Time: %s\n",time); + } + else + { + self.nextthink = self.ltime + 0.1; + //dprint("Train no wait\n"); + } + } + else + { + if(self.level) + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_NONE); + else + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise, 1, ATTN_NORM); + } + + if (self.decap == 0 || self.decap == 2) + if(!self.effects&EF_NODRAW) + self.effects = 0; + else + self.effects=EF_NODRAW; +}; + +void() train_rotate_mp = +{ +entity targ; +vector dir; + + targ = self.enemy; + + if (targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0) + { + dir = self.angles; + dir += targ.mangle; + + if(self.wait) + SUB_CalcAngleMove (dir, self.anglespeed, train_wait_mp); + else + SUB_CalcAngleMove (dir, self.anglespeed, train_next_mp); + } + else if(self.wait) + train_wait_mp(); + else + train_next_mp(); +}; + +void() train_next_mp = +{//NOTE!!! WHEN A TRAIN HAS A WAIT <= TIME, IT STOPS!!! +entity oldtarg,targ; +vector dir,end_spot; +vector slope_angles; +/* if(self.movechain) + { + dprint(self.movechain.model); + dprint(" moving\n"); + } +*/ +//float targ_aspeed;//,targ_speed; + +/* + dprint("Next target: "); + dprint(self.target); + dprint("\n"); +*/ + + targ = find (world, targetname, self.target); + self.target = targ.target; + + if (!self.decap && self.spawnflags & TRAIN_RETURN) + if (self.noise3 == targ.targetname) + self.decap = 2; + + if (!self.target) + objerror ("train_next: no next target"); +// else +// dprint("Found next target\n"); + + if (targ.wait) + self.wait = targ.wait; +// if(self.wait) +// dprintf("My wait is: %s\n",self.wait); + +// else +// self.wait = 0; + + oldtarg=self.enemy; + self.enemy = targ; + + if(self.level) + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_LOOP); + else + sound (self, CHAN_UPDATE+PHS_OVERRIDE_R, self.noise1, 1, ATTN_LOOP); + +/*Used to not set self speed to targ speed + if(targ.speed) + targ_speed=targ.speed; + else + targ_speed = self.speed; +*/ + if(targ.speed) + self.speed=targ.speed; + +// dprintf("Train's speed now: %s\n",targ_speed); + + if(self.spawnflags&SLOPE) + { +// dprint("Train auto-sloping\n"); +//Make everything 0 - 359 + while(self.angles_x>359) + self.angles_x -= 360; + while(self.angles_x<0) + self.angles_x += 360; +// while(self.angles_y>359) +// self.angles_y -= 360; +// while(self.angles_y<0) +// self.angles_y += 360; + + slope_angles = vectoangles(normalize(targ.origin - self.origin)); + + while(slope_angles_x>359) + slope_angles_x -= 360; + while(slope_angles_x<0) + slope_angles_x += 360; +// while(slope_angles_y>359) +// slope_angles_y -= 360; +// while(slope_angles_y<0) +// slope_angles_y += 360; + + targ.mangle_x = self.angles_x - slope_angles_x; +// targ.mangle_y = self.angles_y - slope_angles_y; + +// if(targ.mangle_x<-180) +// targ.mangle_x+=360; +// else if(targ.mangle_x>180) +// targ.mangle_x-=360; +// if(targ.mangle_y<-180) +// targ.mangle_y+=360; +// else if(targ.mangle_y>180) +// targ.mangle_y-=360; + +/* +Don't mod roll + if(targ.mangle_z>180) + targ.mangle_z= (180 - (targ.mangle_z - 180))*-1; + else if(targ.mangle_z<-180) + targ.mangle_z= 180 - (targ.mangle_z + 180); +*/ +// dprintv("Target mangle: %s\n",targ.mangle); + } + + if(self.spawnflags&USE_ORIGIN&&self.origin!='0 0 0') + end_spot = targ.origin; + else + end_spot = targ.origin - self.mins; + + if (!self.spawnflags&ANGLE_WAIT&&(targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0)) + { + dir = self.angles; + dir += targ.mangle; + +// dprint ("move and rotate\n"); + if(targ.anglespeed) + self.anglespeed=targ.anglespeed; + + if(targ.spawnflags&SYNCH||self.spawnflags&SLOPE) + { + if(!self.wait) + SUB_CalcMoveAndAngleInit (end_spot, self.speed, dir, self.anglespeed, train_next_mp,TRUE); + else + SUB_CalcMoveAndAngleInit (end_spot, self.speed, dir, self.anglespeed, train_wait_mp,TRUE); + } + else + { + if(!self.wait) + SUB_CalcMoveAndAngleInit (end_spot, self.speed, dir, self.anglespeed, train_next_mp,FALSE); + else + SUB_CalcMoveAndAngleInit (end_spot, self.speed, dir, self.anglespeed, train_wait_mp,FALSE); + } + } + else + { + + if(targ.mangle_x != 0 || targ.mangle_y != 0 || targ.mangle_z != 0) + { +// dprint ("move then rotate\n"); + SUB_CalcMove (end_spot, self.speed, train_rotate_mp); + } + else + { +// dprintv("move- no rotate %s\n",targ.mangle); + + if(!self.wait) + SUB_CalcMove (end_spot, self.speed, train_next_mp); + else + SUB_CalcMove (end_spot, self.speed, train_wait_mp); + } + } + + if (self.spawnflags & TRAIN_WAITTRIG) + self.decap = 2; +}; + +void() func_train_find_mp = +{ +entity targ; + + targ = find (world, targetname, self.target); + self.enemy=targ; + self.target = targ.target; + if(self.spawnflags&USE_ORIGIN&&self.origin!='0 0 0') + setorigin (self, targ.origin); + else + setorigin (self, targ.origin - self.mins); + + if(targ.mangle_x) + { +// dprint("taking path's x\n"); + self.angles_x = targ.mangle_x; + } + if(targ.mangle_y) + { +// dprint("taking path's y\n"); + self.angles_y = targ.mangle_y; + } + if(targ.mangle_z) + { +// dprint("taking path's z\n"); + self.angles_z = targ.mangle_z; + } + + if (!self.targetname) + { // not triggered, so start immediately + self.decap = 1; + self.nextthink = self.ltime + 0.1; + self.think = train_next_mp; + } +}; + +/*QUAKED func_train_mp (0 .5 .8) ? invisible TOGGLE RETURN TRANSLUCENT SLOPE ANGLEMATCH USE_ORIGIN ANGLEWAIT +Hexen 2 MISSION PACK version Trains + +Remember: angles and mangles are 'x y z' format where x = pitch, y = yaw and z = roll + +Trains are moving platforms that players can ride. +The targets origin specifies the min point of the train at each corner. +The train spawns at the first target it is pointing at. +If the train is the target of a button or trigger, it will not begin moving until activated. +speed default 100 +dmg default 2 +soundtype +0) none +1) ratchet metal +2) pullies +3) sliding +4) normal? +5) medival? +6) guillotine? +7) chain? +8) Rolling boulder +9) Spinning prayer wheel + +if train is only moving to one spot +"angle" - to tell it's direction +"distance" - in pixels, how far to move +"speed" - how fast it moves between spots (default=100) +"anglespeed" - how fast it rotates to a new angle (default = 100) +"wait" - -1 will make it stop forever, -2 will make it blow up (you can put the waits on the pathcorners and it will take the wait from there. + -3 will make the train stop and wait for the next trigger event (don't blame me!- Blame Josh!) +NOTE: If you give it a wait of -2, be sure to set the thingtype. + +"pausetime" - How long to wait after getting to the end of it's path before blowing up, default is 0 + +"weaponmodel" - A model file to use instead of train visuals, but will have the blocking shape of the train you make +WARNING: use "directory/model.mdl" format- NOT a "\"!!! +NOTE: You should use a origin brush in the train and make sure you know where the origin of the model you're using is at. +if set to "models/null.spr", it will effectively make an invisible train. + +thingtype - type of chunks and sprites it will generate + 0 - glass + 1 - grey stone (default for trains) + 2 - wood + 3 - metal + 4 - flesh + 5 - fire + 6 - clay + 7 - leaves + 8 - hay + 9 - brown stone + 10 - cloth + 11 - wood & leaf + 12 - wood & metal + 13 - wood stone + 14 - metal stone + 15 - metal cloth + 16 - spider web + 17 - stained glass + 18 - ice + 19 - clear glass + 20 - red glass + +The train will modify it's angles by whatever angles it's next path point has, so if it heads towards a path corner with an angle of '0 90 0', the train will rotate '0 90 0' on it's way to the pathpoint. If you make the anglespeed the same as the angle, the turn should finish right as the train gets to the new spot. + +NOTE: A path_corner using spawnflag "SYNCH" will make the train automatically calculate a new anglespeed based on the distance it's going and will finish the turn at the same time the move is done. + +As usual, any rotating brush needs an origin brush. + +"abslight" - to set the absolute light level +"angles" - only used for models attached to trains. +"level" - if set to "1" sounds from train have no attenuation (can always be heard no matter how far player is away) + +if "invisible" is checked, train will be invisible and not solid +SLOPE - Train will automatically find the pitch and yaw it needs to get from path_corner to path_corner +ANGLEMATCH - If it has an attached model, that model's angles will change with the train's +USE_ORIGIN - Use an origin brush as origin for moving along path, not south-west-bottom corner. +ANGLE_WAIT - Train will not change angles until it reached path_corner, and will not move again until that angle movement is done +*/ +void() func_train_mp = +{ +entity targ; + + if(!world.spawnflags&MISSIONPACK) + { + func_train(); + return; + } + + if(self.dmg==666) + if(mapname=="tibet9") + self.dmg=50; + + self.decap = 0; + + if (self.spawnflags & TRAIN_GLOW) + { + self.solid=SOLID_NOT; + self.effects(+)EF_NODRAW; + } + else + { + self.solid = SOLID_BSP; + setmodel (self, self.model); + if(self.weaponmodel) + { + self.movechain=spawn(); + self.movechain.model=self.weaponmodel; + self.movechain.movetype=MOVETYPE_NOCLIP; + self.movechain.solid=SOLID_NOT; + precache_model2(self.movechain.model); + setmodel (self.movechain, self.movechain.model); + setorigin(self.movechain,self.origin); + self.effects(+)EF_NODRAW; + self.weaponmodel=""; + self.movechain.angles=self.angles; + self.angles='0 0 0'; + if(self.abslight) + { + self.movechain.drawflags(+)MLS_ABSLIGHT; + self.movechain.abslight=self.abslight; + } + if(self.spawnflags&ANGLEMATCH)//Match angles + self.movechain.flags(+)FL_MOVECHAIN_ANGLE; + } + } + + if (!self.speed) + self.speed = 100; + + if (!self.anglespeed) + self.anglespeed = 100; + + if (!self.target) + objerror ("func_train without a target"); + + if (!self.dmg) + self.dmg = 2; + + if(self.health) + { + self.takedamage=DAMAGE_YES; + self.th_die=chunk_death; + if(!self.thingtype) + self.thingtype=1; + } + + if(self.soundtype==1) + { + self.noise = "plats/train2.wav"; + self.noise1 = "plats/train1.wav"; + } + else if(self.soundtype==2) + { + self.noise = "plats/pulyplt2.wav"; + self.noise1 = "plats/pulyplt1.wav"; + } + else if(self.soundtype==3) + { + self.noise = "plats/platstp.wav"; + precache_sound3("plats/platstp.wav"); + self.noise1 = "plats/platslid.wav"; + precache_sound3("plats/platslid.wav"); + } + else if(self.soundtype==4) + { + self.noise = "plats/plat2.wav"; + self.noise1 = "plats/plat1.wav"; + } + else if(self.soundtype==5) + { + self.noise = "plats/medplat2.wav"; + self.noise1 = "plats/medplat1.wav"; + } + else if(self.soundtype==6) + { + self.noise = "plats/guiltin2.wav"; + self.noise1 = "plats/guiltin1.wav"; + } + else if(self.soundtype==7) + { + self.noise = "plats/chainplt2.wav"; + self.noise1 = "plats/chainplt1.wav"; + } + else if(self.soundtype==8) + { + self.noise = "plats/boldstop.wav"; //stop + precache_sound3("plats/boldstop.wav"); + self.noise1 = "plats/boldroll.wav"; //moving + precache_sound3("plats/boldroll.wav"); + } + else if(self.soundtype==9) + { + self.noise = "plats/pwheel2.wav"; + precache_sound3("plats/pwheel2.wav"); + self.noise1 = "plats/pwheel1.wav"; + precache_sound3("plats/pwheel1.wav"); + } + else + self.noise = self.noise1 = "misc/null.wav"; + precache_sound (self.noise); + precache_sound (self.noise1); + + if(self.wait==-2) + { + if(!self.thingtype) + self.thingtype=1; + if(!self.th_die) + self.th_die=chunk_death; + } + + self.cnt = 1; + self.movetype = MOVETYPE_PUSH; + self.blocked = train_blocked_mp; + self.use = train_use_mp; +// self.classname = "train"; + + setsize (self, self.mins , self.maxs); + setorigin (self, self.origin); + + targ = find(world, target, self.target); + self.noise3 = targ.target; + + if(self.spawnflags&SLOPE) + self.spawnflags(+)SYNCH; + + if (self.abslight) + self.drawflags(+)MLS_ABSLIGHT; + + if (self.spawnflags & 8) + { + self.drawflags(+)DRF_TRANSLUCENT; + self.solid = SOLID_NOT; + } + + +// start trains on the second frame, to make sure their targets have had +// a chance to spawn + self.nextthink = self.ltime + 0.1; + self.think = func_train_find_mp; +}; + diff --git a/precache.hc b/precache.hc new file mode 100644 index 0000000..30f6053 --- /dev/null +++ b/precache.hc @@ -0,0 +1,1277 @@ +/* + * $Header: /HexenWorld/Siege/precache.hc 24 6/16/98 12:00p Ggribb $ + */ + +// called by worldspawn +void() W_Precache = +{ + precache_sound ("raven/kiltorch.wav"); // player torch dying + precache_sound ("raven/littorch.wav"); // player torch being lit + precache_sound ("raven/fire1.wav"); // player torch burning + + precache_sound ("rj/steve.wav"); + + precache_sound ("weapons/ric1.wav"); // ricochet (used in c code) + precache_sound ("weapons/ric2.wav"); // ricochet (used in c code) + precache_sound ("weapons/ric3.wav"); // ricochet (used in c code) + precache_sound ("weapons/tink1.wav"); // ricochet (used in c code) + precache_sound ("weapons/r_exp3.wav"); //Still being used? +// precache_sound ("items/inv2.wav"); //Quake sounds! + + precache_model ("gfx/puff.spr"); + precache_model ("models/ball.mdl"); + precache_model ("models/star.mdl"); +}; + + +// +// these are all of the lumps from the cached.ls files +// +void Precache_lmp (void) +{ + precache_file ("gfx/palette.lmp"); + precache_file ("gfx/colormap.lmp"); + precache_file ("gfx/player.lmp"); + precache_file ("gfx/tinttab.lmp"); + precache_file ("gfx/tinttab2.lmp"); + precache_file ("gfx/invpal.lmp"); + precache_file ("gfx/skin100.lmp"); + precache_file ("gfx/skin101.lmp"); + + precache_file ("strings.txt"); + precache_file ("puzzles.txt"); + precache_file ("maplist.txt"); + + precache_file ("gfx/menu/fontsize.lmp"); + precache_file ("gfx/menu/backtile.lmp"); + precache_file ("gfx/menu/bigfont.lmp"); + precache_file ("gfx/menu/bigfont2.lmp"); + precache_file ("gfx/menu/conback.lmp"); + precache_file ("gfx/menu/fontsize.lmp"); + precache_file ("gfx/menu/help01.lmp"); + precache_file ("gfx/menu/help02.lmp"); + precache_file ("gfx/menu/help03.lmp"); + precache_file ("gfx/menu/help04.lmp"); + precache_file ("gfx/menu/help05.lmp"); + precache_file ("gfx/menu/hplaque.lmp"); + precache_file ("gfx/menu/load.lmp"); + precache_file ("gfx/menu/loading.lmp"); + precache_file ("gfx/menu/menudot1.lmp"); + precache_file ("gfx/menu/menudot2.lmp"); + precache_file ("gfx/menu/menudot3.lmp"); + precache_file ("gfx/menu/menudot4.lmp"); + precache_file ("gfx/menu/menudot5.lmp"); + precache_file ("gfx/menu/menudot6.lmp"); + precache_file ("gfx/menu/menudot7.lmp"); + precache_file ("gfx/menu/menudot8.lmp"); + precache_file ("gfx/menu/paused.lmp"); + precache_file ("gfx/menu/save.lmp"); + precache_file ("gfx/menu/skull0.lmp"); + precache_file ("gfx/menu/skull1.lmp"); + precache_file ("gfx/menu/skull10.lmp"); + precache_file ("gfx/menu/skull11.lmp"); + precache_file ("gfx/menu/skull12.lmp"); + precache_file ("gfx/menu/skull13.lmp"); + precache_file ("gfx/menu/skull14.lmp"); + precache_file ("gfx/menu/skull15.lmp"); + precache_file ("gfx/menu/skull16.lmp"); + precache_file ("gfx/menu/skull17.lmp"); + precache_file ("gfx/menu/skull2.lmp"); + precache_file ("gfx/menu/skull3.lmp"); + precache_file ("gfx/menu/skull4.lmp"); + precache_file ("gfx/menu/skull5.lmp"); + precache_file ("gfx/menu/skull6.lmp"); + precache_file ("gfx/menu/skull7.lmp"); + precache_file ("gfx/menu/skull8.lmp"); + precache_file ("gfx/menu/skull9.lmp"); + precache_file ("gfx/menu/title0.lmp"); + precache_file ("gfx/menu/title1.lmp"); + precache_file ("gfx/menu/title2.lmp"); + precache_file ("gfx/menu/title3.lmp"); + precache_file ("gfx/menu/title4.lmp"); + precache_file ("gfx/menu/title5.lmp"); + precache_file ("gfx/menu/title6.lmp"); + precache_file ("gfx/menu/title7.lmp"); + precache_file ("gfx/menu/title8.lmp"); + + precache_file ("gfx/box_tl.lmp"); + precache_file ("gfx/box_tm.lmp"); + precache_file ("gfx/box_tr.lmp"); + precache_file ("gfx/box_ml.lmp"); + precache_file ("gfx/box_mm.lmp"); + precache_file ("gfx/box_mm2.lmp"); + precache_file ("gfx/box_mr.lmp"); + precache_file ("gfx/box_bl.lmp"); + precache_file ("gfx/box_bm.lmp"); + precache_file ("gfx/box_br.lmp"); + + precache_file ("gfx/cport1.lmp"); + precache_file ("gfx/cport2.lmp"); + precache_file ("gfx/cport3.lmp"); + precache_file ("gfx/cport4.lmp"); + + precache_file ("gfx/menu/netp1.lmp"); + precache_file ("gfx/menu/netp2.lmp"); + precache_file ("gfx/menu/netp3.lmp"); + precache_file ("gfx/menu/netp4.lmp"); + precache_file ("gfx/menu/frame.lmp"); + + // Interface graphics + precache_file ("gfx/topbar1.lmp"); + precache_file ("gfx/topbar2.lmp"); + precache_file ("gfx/topbumpl.lmp"); + precache_file ("gfx/topbumpm.lmp"); + precache_file ("gfx/topbumpr.lmp"); + precache_file ("gfx/bmana.lmp"); + precache_file ("gfx/bmanacov.lmp"); + precache_file ("gfx/gmana.lmp"); + precache_file ("gfx/gmanacov.lmp"); + precache_file ("gfx/hpchain.lmp"); + precache_file ("gfx/hpgem.lmp"); + precache_file ("gfx/chnlcov.lmp"); + precache_file ("gfx/chnrcov.lmp"); + precache_file ("gfx/bmmana.lmp"); + precache_file ("gfx/gmmana.lmp"); + precache_file ("gfx/btmbar1.lmp"); + precache_file ("gfx/btmbar2.lmp"); + precache_file ("gfx/armor1.lmp"); + precache_file ("gfx/armor2.lmp"); + precache_file ("gfx/armor3.lmp"); + precache_file ("gfx/armor4.lmp"); + precache_file ("gfx/ring_f.lmp"); + precache_file ("gfx/ring_w.lmp"); + precache_file ("gfx/ring_t.lmp"); + precache_file ("gfx/ring_r.lmp"); + precache_file ("gfx/artisel.lmp"); + precache_file ("gfx/artinum0.lmp"); + precache_file ("gfx/artinum1.lmp"); + precache_file ("gfx/artinum2.lmp"); + precache_file ("gfx/artinum3.lmp"); + precache_file ("gfx/artinum4.lmp"); + precache_file ("gfx/artinum5.lmp"); + precache_file ("gfx/artinum6.lmp"); + precache_file ("gfx/artinum7.lmp"); + precache_file ("gfx/artinum8.lmp"); + precache_file ("gfx/artinum9.lmp"); + precache_file ("gfx/rngfly1.lmp"); + precache_file ("gfx/rngfly2.lmp"); + precache_file ("gfx/rngfly3.lmp"); + precache_file ("gfx/rngfly4.lmp"); + precache_file ("gfx/rngfly5.lmp"); + precache_file ("gfx/rngfly6.lmp"); + precache_file ("gfx/rngfly7.lmp"); + precache_file ("gfx/rngfly8.lmp"); + precache_file ("gfx/rngfly9.lmp"); + precache_file ("gfx/rngfly10.lmp"); + precache_file ("gfx/rngfly11.lmp"); + precache_file ("gfx/rngfly12.lmp"); + precache_file ("gfx/rngfly13.lmp"); + precache_file ("gfx/rngfly14.lmp"); + precache_file ("gfx/rngfly15.lmp"); + precache_file ("gfx/rngfly16.lmp"); + precache_file ("gfx/rngwtr1.lmp"); + precache_file ("gfx/rngwtr2.lmp"); + precache_file ("gfx/rngwtr3.lmp"); + precache_file ("gfx/rngwtr4.lmp"); + precache_file ("gfx/rngwtr5.lmp"); + precache_file ("gfx/rngwtr6.lmp"); + precache_file ("gfx/rngwtr7.lmp"); + precache_file ("gfx/rngwtr8.lmp"); + precache_file ("gfx/rngwtr9.lmp"); + precache_file ("gfx/rngwtr10.lmp"); + precache_file ("gfx/rngwtr11.lmp"); + precache_file ("gfx/rngwtr12.lmp"); + precache_file ("gfx/rngwtr13.lmp"); + precache_file ("gfx/rngwtr14.lmp"); + precache_file ("gfx/rngwtr15.lmp"); + precache_file ("gfx/rngwtr16.lmp"); + precache_file2 ("gfx/rngtrn1.lmp"); + precache_file2 ("gfx/rngtrn2.lmp"); + precache_file2 ("gfx/rngtrn3.lmp"); + precache_file2 ("gfx/rngtrn4.lmp"); + precache_file2 ("gfx/rngtrn5.lmp"); + precache_file2 ("gfx/rngtrn6.lmp"); + precache_file2 ("gfx/rngtrn7.lmp"); + precache_file2 ("gfx/rngtrn8.lmp"); + precache_file2 ("gfx/rngtrn9.lmp"); + precache_file2 ("gfx/rngtrn10.lmp"); + precache_file2 ("gfx/rngtrn11.lmp"); + precache_file2 ("gfx/rngtrn12.lmp"); + precache_file2 ("gfx/rngtrn13.lmp"); + precache_file2 ("gfx/rngtrn14.lmp"); + precache_file2 ("gfx/rngtrn15.lmp"); + precache_file2 ("gfx/rngtrn16.lmp"); +/* precache_file2 ("gfx/rngreg1.lmp"); + precache_file2 ("gfx/rngreg2.lmp"); + precache_file2 ("gfx/rngreg3.lmp"); + precache_file2 ("gfx/rngreg4.lmp"); + precache_file2 ("gfx/rngreg5.lmp"); + precache_file2 ("gfx/rngreg6.lmp"); + precache_file2 ("gfx/rngreg7.lmp"); + precache_file2 ("gfx/rngreg8.lmp"); + precache_file2 ("gfx/rngreg9.lmp"); + precache_file2 ("gfx/rngreg10.lmp"); + precache_file2 ("gfx/rngreg11.lmp"); + precache_file2 ("gfx/rngreg12.lmp"); + precache_file2 ("gfx/rngreg13.lmp"); + precache_file2 ("gfx/rngreg14.lmp"); + precache_file2 ("gfx/rngreg15.lmp"); + precache_file2 ("gfx/rngreg16.lmp");*/ + precache_file ("gfx/pwrbook1.lmp"); + precache_file ("gfx/pwrbook2.lmp"); + precache_file ("gfx/pwrbook3.lmp"); + precache_file ("gfx/pwrbook4.lmp"); + precache_file ("gfx/pwrbook5.lmp"); + precache_file ("gfx/pwrbook6.lmp"); + precache_file ("gfx/pwrbook7.lmp"); + precache_file ("gfx/pwrbook8.lmp"); + precache_file ("gfx/pwrbook9.lmp"); + precache_file ("gfx/pwrbook10.lmp"); + precache_file ("gfx/pwrbook11.lmp"); + precache_file ("gfx/pwrbook12.lmp"); + precache_file ("gfx/pwrbook13.lmp"); + precache_file ("gfx/pwrbook14.lmp"); + precache_file ("gfx/pwrbook15.lmp"); + precache_file ("gfx/pwrbook16.lmp"); + precache_file ("gfx/durhst1.lmp"); + precache_file ("gfx/durhst2.lmp"); + precache_file ("gfx/durhst3.lmp"); + precache_file ("gfx/durhst4.lmp"); + precache_file ("gfx/durhst5.lmp"); + precache_file ("gfx/durhst6.lmp"); + precache_file ("gfx/durhst7.lmp"); + precache_file ("gfx/durhst8.lmp"); + precache_file ("gfx/durhst9.lmp"); + precache_file ("gfx/durhst10.lmp"); + precache_file ("gfx/durhst11.lmp"); + precache_file ("gfx/durhst12.lmp"); + precache_file ("gfx/durhst13.lmp"); + precache_file ("gfx/durhst14.lmp"); + precache_file ("gfx/durhst15.lmp"); + precache_file ("gfx/durhst16.lmp"); + precache_file ("gfx/durshd1.lmp"); + precache_file ("gfx/durshd2.lmp"); + precache_file ("gfx/durshd3.lmp"); + precache_file ("gfx/durshd4.lmp"); + precache_file ("gfx/durshd5.lmp"); + precache_file ("gfx/durshd6.lmp"); + precache_file ("gfx/durshd7.lmp"); + precache_file ("gfx/durshd8.lmp"); + precache_file ("gfx/durshd9.lmp"); + precache_file ("gfx/durshd10.lmp"); + precache_file ("gfx/durshd11.lmp"); + precache_file ("gfx/durshd12.lmp"); + precache_file ("gfx/durshd13.lmp"); + precache_file ("gfx/durshd14.lmp"); + precache_file ("gfx/durshd15.lmp"); + precache_file ("gfx/durshd16.lmp"); + precache_file ("gfx/arti00.lmp"); + precache_file ("gfx/arti01.lmp"); + precache_file ("gfx/arti02.lmp"); + precache_file ("gfx/arti03.lmp"); + precache_file ("gfx/arti04.lmp"); + precache_file ("gfx/arti05.lmp"); + precache_file ("gfx/arti06.lmp"); + precache_file ("gfx/arti07.lmp"); + precache_file ("gfx/arti08.lmp"); + precache_file ("gfx/arti09.lmp"); + precache_file ("gfx/arti10.lmp"); + precache_file ("gfx/arti11.lmp"); + precache_file ("gfx/arti12.lmp"); + precache_file ("gfx/arti13.lmp"); + precache_file ("gfx/arti14.lmp"); + + precache_file ("gfx/ringhlth.lmp"); + precache_file ("gfx/rhlthcvr.lmp"); + + precache_file2 ("gfx/rhlthcv2.lmp"); + + precache_file ("gfx/castle.lmp"); + precache_file2 ("gfx/meso.lmp"); + precache_file2 ("gfx/egypt.lmp"); + precache_file2 ("gfx/roman.lmp"); + + precache_file2 ("gfx/end-1.lmp"); + precache_file2 ("gfx/end-2.lmp"); + precache_file2 ("gfx/end-3.lmp"); + + precache_file ("gfx/defwin.lmp"); + precache_file ("gfx/attwin.lmp"); + precache_file ("gfx/attwin2.lmp"); +/* + precache_file (""); + precache_file (""); + precache_file (""); + precache_file (""); + precache_file (""); + precache_file (""); + precache_file (""); +*/ + + // Puzzle Pieces + precache_file2("models/puzzle/staff.mdl"); + precache_file2("models/puzzle/e1.mdl"); + precache_file2("models/puzzle/e2.mdl"); + precache_file2("models/puzzle/e3.mdl"); + precache_file2("models/puzzle/e4.mdl"); + precache_file2("models/puzzle/e5.mdl"); + precache_file2("models/puzzle/e6.mdl"); + precache_file2("models/puzzle/m1.mdl"); + precache_file2("models/puzzle/m2.mdl"); + precache_file2("models/puzzle/m3.mdl"); + precache_file2("models/puzzle/m4.mdl"); + precache_file2("models/puzzle/m5.mdl"); + precache_file2("models/puzzle/s1.mdl"); + precache_file2("models/puzzle/s2.mdl"); + precache_file2("models/puzzle/scepter.mdl"); + precache_file("models/puzzle/keep1.mdl"); + precache_file("models/puzzle/keep2.mdl"); + precache_file("models/puzzle/keep3.mdl"); + precache_file2("models/puzzle/ra1.mdl"); + precache_file2("models/puzzle/r1.mdl"); + precache_file2("models/puzzle/r2.mdl"); + precache_file2("models/puzzle/r3.mdl"); + precache_file2("models/puzzle/r4.mdl"); + precache_file2("models/puzzle/r5.mdl"); + precache_file2("models/puzzle/r6.mdl"); + precache_file2("models/puzzle/r7.mdl"); + precache_file2("models/puzzle/r8.mdl"); + precache_file3("models/puzzle/trkey.mdl"); + precache_file("models/puzzle/cskey.mdl"); + precache_file3("models/puzzle/amult.mdl"); + precache_file3("models/puzzle/glass.mdl"); + precache_file3("models/puzzle/lens.mdl"); + precache_file3("models/puzzle/shovl.mdl"); + precache_file3("models/puzzle/scrol.mdl"); + precache_file2("models/puzzle/e4.mdl"); + precache_file2("models/puzzle/e5.mdl"); + precache_file2("models/puzzle/e6.mdl"); + precache_file3("models/puzzle/sand.mdl"); + precache_file2("models/puzzle/air.mdl"); + precache_file2("models/puzzle/earth.mdl"); + precache_file2("models/puzzle/water.mdl"); + precache_file2("models/puzzle/fire.mdl"); + precache_file2("models/puzzle/scept.mdl"); + precache_file2("models/puzzle/eyeh.mdl"); + precache_file2("models/puzzle/clueb.mdl"); + precache_file2("models/puzzle/lcrwn.mdl"); + precache_file2("models/puzzle/ucrwn.mdl"); + precache_file("models/puzzle/mithl.mdl"); + precache_file3("models/puzzle/stkey.mdl"); + precache_file3("models/puzzle/takey.mdl"); + precache_file2("models/puzzle/ankey.mdl"); + precache_file2("models/puzzle/stime.mdl"); + precache_file2("models/puzzle/speye.mdl"); + precache_file2("models/puzzle/rcjem.mdl"); + precache_file2("models/puzzle/music.mdl"); + precache_file2("models/puzzle/silver.mdl"); + precache_file2("models/puzzle/cross.mdl"); + precache_file2("models/puzzle/holycrss.mdl"); + precache_file2("models/puzzle/gsphere.mdl"); + precache_file2("models/puzzle/prybar.mdl"); + precache_file2("models/puzzle/soul.mdl"); + precache_file2("models/puzzle/mage.mdl"); + precache_file2("models/puzzle/rakey.mdl"); + precache_file2("models/puzzle/h-book.mdl"); + + + precache_file2("gfx/puzzle/staff.lmp"); + precache_file2("gfx/puzzle/e1.lmp"); + precache_file2("gfx/puzzle/e2.lmp"); + precache_file2("gfx/puzzle/e3.lmp"); + precache_file2("gfx/puzzle/e4.lmp"); + precache_file2("gfx/puzzle/e5.lmp"); + precache_file2("gfx/puzzle/e6.lmp"); + precache_file2("gfx/puzzle/m1.lmp"); + precache_file2("gfx/puzzle/m2.lmp"); + precache_file2("gfx/puzzle/m3.lmp"); + precache_file2("gfx/puzzle/m4.lmp"); + precache_file2("gfx/puzzle/m5.lmp"); + precache_file2("gfx/puzzle/s1.lmp"); + precache_file2("gfx/puzzle/s2.lmp"); + precache_file2("gfx/puzzle/scepter.lmp"); + precache_file("gfx/puzzle/keep1.lmp"); + precache_file("gfx/puzzle/keep2.lmp"); + precache_file("gfx/puzzle/keep3.lmp"); + precache_file2("gfx/puzzle/ra1.lmp"); + precache_file2("gfx/puzzle/r1.lmp"); + precache_file2("gfx/puzzle/r2.lmp"); + precache_file2("gfx/puzzle/r3.lmp"); + precache_file2("gfx/puzzle/r4.lmp"); + precache_file2("gfx/puzzle/r5.lmp"); + precache_file2("gfx/puzzle/r6.lmp"); + precache_file2("gfx/puzzle/r7.lmp"); + precache_file2("gfx/puzzle/r8.lmp"); + precache_file3("gfx/puzzle/trkey.lmp"); + precache_file("gfx/puzzle/cskey.lmp"); + precache_file3("gfx/puzzle/amult.lmp"); + precache_file3("gfx/puzzle/glass.lmp"); + precache_file3("gfx/puzzle/lens.lmp"); + precache_file3("gfx/puzzle/shovl.lmp"); + precache_file3("gfx/puzzle/scrol.lmp"); + precache_file2("gfx/puzzle/e4.lmp"); + precache_file2("gfx/puzzle/e5.lmp"); + precache_file2("gfx/puzzle/e6.lmp"); + precache_file3("gfx/puzzle/sand.lmp"); + precache_file2("gfx/puzzle/air.lmp"); + precache_file2("gfx/puzzle/earth.lmp"); + precache_file2("gfx/puzzle/water.lmp"); + precache_file2("gfx/puzzle/fire.lmp"); + precache_file2("gfx/puzzle/scept.lmp"); + precache_file2("gfx/puzzle/eyeh.lmp"); + precache_file2("gfx/puzzle/clueb.lmp"); + precache_file2("gfx/puzzle/lcrwn.lmp"); + precache_file2("gfx/puzzle/ucrwn.lmp"); + precache_file("gfx/puzzle/mithl.lmp"); + precache_file3("gfx/puzzle/stkey.lmp"); + precache_file3("gfx/puzzle/takey.lmp"); + precache_file2("gfx/puzzle/ankey.lmp"); + precache_file2("gfx/puzzle/stime.lmp"); + precache_file2("gfx/puzzle/speye.lmp"); + precache_file2("gfx/puzzle/rcjem.lmp"); + precache_file2("gfx/puzzle/music.lmp"); + precache_file2("gfx/puzzle/silver.lmp"); + precache_file2("gfx/puzzle/cross.lmp"); + precache_file2("gfx/puzzle/holycrss.lmp"); + precache_file2("gfx/puzzle/gsphere.lmp"); + precache_file2("gfx/puzzle/prybar.lmp"); + precache_file2("gfx/puzzle/soul.lmp"); + precache_file2("gfx/puzzle/mage.lmp"); + precache_file2("gfx/puzzle/rakey.lmp"); + precache_file2("gfx/puzzle/h-book.lmp"); + + //RIDER_INIT + precache_file3 ("models/boss/shaft.mdl"); + precache_file3 ("models/boss/circle.mdl"); + precache_file3 ("models/boss/star.mdl"); +// precache_sound3 ("famine/flashdie.wav"); + + //EIDOLON + precache_file2 ("models/boss/smaleido.mdl"); + precache_file2 ("models/boss/bigeido.mdl"); + precache_file2 ("models/eidoball.mdl"); + precache_file2 ("models/eidoflam.spr"); + precache_file2 ("models/glowball.mdl"); + precache_file2 ("models/boss/chaosorb.mdl"); + precache_sound3 ("eidolon/roar.wav"); + precache_sound3 ("eidolon/pain.wav"); //Hurt +// precache_sound3 ("eidolon/death.wav"); //Dies- long and agonizing +// precache_sound3 ("eidolon/fakedie.wav");//1st death- fake +// precache_sound3 ("eidolon/spell.wav"); //Spell attack (tracking globes) +// precache_sound3 ("eidolon/stomp.wav"); //Hot-steppin' +// precache_sound3 ("eidolon/fireball.wav"); //Launching Nasty fireballs +// precache_sound3 ("eidolon/flamstrt.wav"); // +// precache_sound3 ("eidolon/flambrth.wav"); // +// precache_sound3 ("eidolon/flamend.wav"); // + precache_sound3 ("eidolon/growl.wav"); // +// precache_sound3 ("eidolon/chrgstrt.wav"); //Orb starts recharging Eido +// precache_sound3 ("eidolon/orbhurt.wav"); //Orb gets hit +// precache_sound3 ("eidolon/orbxpld.wav"); //Orb gets destroyed +// precache_sound3 ("eidolon/orbpulse.wav"); //Orb pulsating + + //PESTILENCE + precache_file2 ("models/boss/boar.mdl"); + precache_file2 ("models/boss/pstrider.mdl"); + precache_file2 ("models/boss/hive.mdl"); + precache_file2 ("models/boss/swarm.mdl"); + precache_file2 ("models/boss/shaft.mdl"); + precache_file2 ("models/pestshot.mdl"); + precache_file2 ("sound/pest/snort.wav"); + precache_file2 ("sound/pest/clop1.wav"); + precache_file2 ("sound/pest/clop2.wav"); + precache_file2 ("sound/pest/clop3.wav"); + precache_file2 ("sound/pest/gallop.wav"); + precache_file2 ("sound/pest/sight.wav"); + precache_file2 ("sound/pest/sting1.wav"); + precache_file2 ("sound/pest/sting2.wav"); + precache_file2 ("sound/pest/sting3.wav"); + precache_file2 ("sound/pest/buzz.wav"); + precache_file2 ("sound/pest/hivehit.wav"); + precache_file2 ("sound/pest/xbowfire.wav"); + precache_file2 ("sound/pest/xbowhit.wav"); + precache_file2 ("sound/pest/die.wav"); + precache_file2 ("sound/pest/charge.wav"); + precache_file2 ("sound/pest/laugh.wav"); + precache_file2 ("sound/pest/snort2.wav"); + + // Famine Rider + precache_file3 ("models/boss/famhorse.mdl"); + precache_file3 ("models/boss/famrider.mdl"); + precache_file3 ("models/famshot.mdl"); + precache_file3 ("sound/famine/die.wav"); + precache_file3 ("sound/famine/laugh.wav"); + precache_file3 ("sound/famine/whinny.wav"); + precache_file3 ("sound/famine/pull.wav"); + precache_file3 ("sound/famine/shot.wav"); + precache_file3 ("sound/famine/snort.wav"); + precache_file3 ("sound/famine/clop1.wav"); + precache_file3 ("sound/famine/clop2.wav"); + precache_file3 ("sound/famine/clop3.wav"); + precache_file3 ("sound/misc/null.wav"); + precache_file3 ("sound/raven/blast.wav"); + precache_file3 ("sound/skullwiz/blinkout.wav"); + precache_file3 ("sound/skullwiz/blinkin.wav"); + + // War Rider + precache_file2 ("models/boss/warhorse.mdl"); + precache_file2 ("models/boss/warrider.mdl"); + precache_file2 ("models/boss/waraxe.mdl"); + precache_file2 ("sound/war/fire_big.wav"); + precache_file2 ("sound/war/die.wav"); + precache_file2 ("sound/war/laugh.wav"); + precache_file2 ("sound/war/laugh_sm.wav"); + precache_file2 ("sound/war/fire.wav"); + precache_file2 ("sound/war/whinny.wav"); + precache_file2 ("sound/war/whinbig.wav"); + precache_file2 ("sound/boss/wartrot1.wav"); + precache_file2 ("sound/boss/wartrot2.wav"); + precache_file2 ("sound/boss/wartrot3.wav"); + + // Death Rider + precache_file2 ("models/boss/dthhorse.mdl"); + precache_file2 ("models/boss/dthrider.mdl"); + precache_file2 ("models/famshot.mdl"); + precache_file2 ("models/boss/bone1.mdl"); + precache_file2 ("models/boss/bone2.mdl"); + precache_file2 ("models/boss/bone3.mdl"); + precache_file2 ("models/boss/bone4.mdl"); + precache_file2 ("models/boss/bone5.mdl"); + precache_file2 ("models/boss/bone6.mdl"); + precache_file2 ("models/mumshot.mdl"); + precache_file2 ("models/booberry.mdl"); + precache_file2 ("sound/mummy/mislfire.wav"); + precache_file2 ("sound/eidolon/flamend.wav"); + precache_file2 ("sound/misc/fburn_bg.wav"); + precache_file2 ("sound/death/fout.wav"); + precache_file2 ("sound/death/dthdie.wav"); + precache_file2 ("sound/death/dthfire.wav"); + precache_file2 ("sound/death/victory.wav"); + precache_file2 ("sound/death/dthlaugh.wav"); + precache_file2 ("sound/death/clop.wav"); + precache_file2 ("sound/death/clop1.wav"); + precache_file2 ("sound/death/clop2.wav"); + precache_file2 ("sound/death/clop3.wav"); + precache_file2 ("sound/death/shot.wav"); + precache_file2 ("sound/ambience/moan1.wav"); + precache_file2 ("sound/ambience/moan2.wav"); + precache_file2 ("sound/ambience/moan3.wav"); +} + + +//********************************************** +// *************** Raven sounds +//********************************************** +void Precache_wav (void) +{ +//DEMO + +//Miscellaneous + precache_sound ("misc/drip.wav"); //Ambience +// precache_sound ("misc/bshatter.wav"); //Burnt thing breaking + precache_sound ("misc/sshatter.wav"); //Stone thing breaking + precache_sound ("misc/pushmetl.wav"); //Pushing different materials- metal + precache_sound ("misc/pushwood.wav"); //Wood + precache_sound ("misc/pushston.wav"); //Stone + precache_sound ("misc/fout.wav"); //Fire doused + precache_sound ("misc/fburn_sm.wav"); //Small fire burning + precache_sound ("misc/fburn_md.wav"); //Medium fire buring + precache_sound ("misc/fburn_bg.wav"); //Big ol' blaze! + precache_sound ("misc/decomp.wav"); //Decomposing sound- actually used for blood squirts +// precache_sound ("misc/camera.wav"); //View through camera + precache_sound ("misc/hith2o.wav"); // thing landing in water + precache_sound ("misc/lighthit.wav"); //Something hit by lightning + precache_sound ("misc/teleprt1.wav"); // teleport sounds- teleport coin + precache_sound ("misc/teleprt2.wav"); + precache_sound ("misc/teleprt3.wav"); + precache_sound ("misc/teleprt4.wav"); + precache_sound ("misc/teleprt5.wav"); + precache_sound ("misc/comm.wav"); // communication + precache_sound ("misc/talk.wav"); // communication +// precache_sound ("raven/squawk.wav"); //Ambient raven + precache_sound ("raven/blast.wav"); + precache_sound ("doors/baddoor.wav"); // Bad attempt to open a door + precache_sound ("buttons/switch04.wav"); // used by the trip mine + +//FX + precache_sound ("fx/glassbrk.wav"); // Glass breaking + precache_sound ("fx/woodbrk.wav"); // Wood breaking + precache_sound ("fx/wallbrk.wav"); // Stone breaking + precache_sound ("fx/metalbrk.wav"); // Metal breaking + precache_sound ("fx/claybrk.wav"); // Clay pot breaking + precache_sound ("fx/leafbrk.wav"); // Leaves breaking (bush or tree) + precache_sound ("fx/clothbrk.wav"); // Cloth breaking (rug) + precache_sound ("fx/thngland.wav"); // landing thud + precache_sound ("misc/null.wav"); // null sound to stop other sounds from playing + +//ITEMS and ARTIFACTS + precache_sound ("weapons/ammopkup.wav");// Backpack pick up + precache_sound ("weapons/weappkup.wav");// weapon pick up + precache_sound ("items/artpkup.wav"); //Artifact pick up + precache_sound ("misc/sheep1.wav"); //In case someone uses Lambinator + precache_sound ("misc/sheep2.wav"); + precache_sound ("misc/sheep3.wav"); + precache_sound ("misc/sheepfly.wav"); //Sheep launched from catapult!!! + precache_sound ("spider/bite.wav"); //Sheep bite + precache_sound ("items/itempkup.wav"); + precache_sound ("items/itmspawn.wav"); // item respawn sound + precache_sound ("items/ringpkup.wav"); // Picking up a ring + precache_sound ("items/artpkup.wav"); + precache_sound ("items/armrpkup.wav"); + precache_sound ("misc/warning.wav"); //glyph about to explode +// precache_sound ("crusader/sunhum.wav"); + //Summoning Stone + precache_sound ("imp/upbig.wav"); + precache_sound ("imp/diebig.wav"); + precache_sound ("imp/swoophit.wav"); + precache_sound ("imp/swoopbig.wav"); + precache_sound ("imp/flybig.wav"); + precache_sound ("imp/fireball.wav"); + precache_sound ("imp/shard.wav"); + precache_sound ("hydra/turn-s.wav"); + +//SHARED PLAYER SOUNDS + //General body/physics sounds + precache_sound ("raven/outwater.wav"); // leaving water sound + precache_sound ("raven/inh2o.wav"); // player in water + precache_sound ("raven/inlava.wav"); // player enter lava + precache_sound ("player/h2ojmp.wav"); // player jumping into water + precache_sound ("player/swim1.wav"); // swimming + precache_sound ("player/swim2.wav"); // swimming + precache_sound ("player/land.wav"); + //Player pain/death sounds + precache_sound ("player/leave.wav"); // leaving deathmatch + precache_sound ("player/telefrag.wav"); // telefrag death + precache_sound ("player/decap.wav"); // Decapitation sound + precache_sound ("player/megagib.wav"); //Really nasty explosive death + precache_sound ("player/gib1.wav"); // player gib sound + precache_sound ("player/gib2.wav"); // player gib sound +// precache_sound ("player/slimbrn1.wav"); // player enter slime + //General weapon sounds + precache_sound ("misc/whoosh.wav"); //Throwing grenades, swing weapons, etc. + precache_sound ("weapons/unsheath.wav"); //Unsheath bladed weapon + precache_sound ("weapons/slash.wav"); //bladed weapon cuts flesh + precache_sound ("weapons/met2flsh.wav"); //Metal impact sounds + precache_sound ("weapons/met2wd.wav"); + precache_sound ("weapons/met2stn.wav"); + precache_sound ("weapons/met2met.wav"); + precache_sound ("weapons/expsmall.wav"); //Small explosion + precache_sound ("weapons/explode.wav"); //Normal explosion + precache_sound ("weapons/exphuge.wav"); //SHA-BOOOOMMM!!! + precache_sound ("weapons/hithurt2.wav"); // Damaging non-flesh with a melee weapon + precache_sound ("weapons/hitwall.wav"); // Hitting (not damaging) a wall with a melee weapon + +//PALADIN +//Body sounds + precache_sound ("player/paljmp.wav"); // player jump + precache_sound ("player/pallnd.wav"); // player hurt when landing + precache_sound ("player/paldieh2.wav"); // player dying in water + precache_sound ("player/paldie1.wav"); // player death 1 + precache_sound ("player/paldie2.wav"); // player death 2 + precache_sound ("player/palpain1.wav"); // player pain 1 + precache_sound ("player/palpain2.wav"); // player pain 2 + precache_sound ("player/palgasp1.wav"); // little air + precache_sound ("player/palgasp2.wav"); // no air + precache_sound ("player/paldrown.wav"); // he's drowning + precache_sound ("paladin/devine.wav"); // Devine Intervention +//Weapon sounds + //Gauntlets + precache_sound ("weapons/gaunt1.wav"); + precache_sound ("weapons/gauntht1.wav"); + precache_sound ("weapons/gauntht2.wav"); + //Vorpal Sword + precache_sound ("weapons/vorpswng.wav"); // Vorpal sword swinging + precache_sound ("weapons/vorpht1.wav"); // Vorpal sword hitting something it can damage + precache_sound ("weapons/vorpht2.wav"); // Vorpal sword hitting something it cannot da + + precache_sound ("weapons/vorpturn.wav"); // Vorpal Sword - weapon 2 + precache_sound ("weapons/vorpblst.wav"); + precache_sound ("weapons/vorppwr.wav"); + //Axe + precache_sound ("paladin/axric1.wav"); // Double Headed Axe - weapon 3 + precache_sound ("paladin/axgen.wav"); + precache_sound ("paladin/axgenpr.wav"); + precache_sound ("paladin/axblade.wav"); + //Purifier +// precache_sound ("paladin/purfire.wav"); +// precache_sound ("paladin/purfireb.wav"); + //Glyph: delayed fireball + precache_sound ("weapons/fbfire.wav"); //Delayed fireball explosion sound + + +//ASSASSIN +//Body sounds + precache_sound ("player/assjmp.wav"); // player jump + precache_sound ("player/asslnd.wav"); // player hurt when landing + precache_sound ("player/assdieh2.wav"); // player dying in water + precache_sound ("player/assdie1.wav"); // player death 1 + precache_sound ("player/assdie2.wav"); // player death 2 + precache_sound ("player/asspain1.wav"); // player pain 1 + precache_sound ("player/asspain2.wav"); // player pain 2 + precache_sound ("player/assgasp1.wav"); // little air + precache_sound ("player/assgasp2.wav"); // no air + precache_sound ("player/assdrown.wav"); // she's drowning +//Weapon sounds + //Crossbow + precache_sound ("assassin/arrowfly.wav"); + precache_sound ("assassin/arr2flsh.wav"); + precache_sound ("assassin/arr2wood.wav"); + precache_sound ("assassin/arrowbrk.wav"); + precache_sound ("assassin/firefblt.wav"); + precache_sound ("assassin/firebolt.wav"); + //Grenades + precache_sound ("assassin/gbounce.wav"); + //Scarab Staff +// precache_sound ("assassin/build.wav"); +// precache_sound ("assassin/pincer.wav"); + precache_sound ("assassin/chntear.wav"); +// precache_sound ("assassin/chn2flsh.wav"); + precache_sound ("assassin/chain.wav"); +// precache_sound ("assassin/clink.wav"); +// precache_sound ("assassin/scarab.wav"); +// precache_sound ("assassin/scrbfly.wav"); +// precache_sound ("assassin/spin.wav"); +// precache_sound ("assassin/core.wav"); + precache_sound ("misc/pulse.wav"); //Invincibility + +//REGISTERED====================================================== + +//Shared sounds + precache_sound ("raven/soul.wav"); // noise the soul sphere makes + +//FX + precache_sound ("fx/quake.wav"); + +//CRUSADER + //Warhammer + precache_sound ("crusader/lghtn1.wav"); + precache_sound ("crusader/lghtn2.wav"); + precache_sound ("raven/lightng1.wav"); + //Ice Staff + precache_sound ("crusader/icehit.wav"); +// precache_sound ("crusader/icewall.wav"); +// precache_sound ("crusader/icefire.wav"); +// precache_sound ("misc/tink.wav"); //Ice shots bounce +// precache_sound ("crusader/blizfire.wav"); +// precache_sound ("crusader/blizzard.wav"); +// precache_sound ("crusader/frozen.wav"); +// precache_sound ("misc/icestatx.wav"); //Ice statue breaking + //Meteor Staff +// precache_sound ("crusader/metfire.wav"); + precache_sound ("misc/rubble.wav"); //Meteor bits fall, stoned player bits fall (from Medusa) +// precache_sound ("crusader/torngo.wav"); +// precache_sound ("crusader/tornado.wav"); + //Sunstaff +// precache_sound ("crusader/sunstart.wav"); + precache_sound ("crusader/sunhit.wav"); + +//NECROMANCER + //Sickle + precache_sound ("weapons/drain.wav"); + //Magic Missiles + precache_sound ("necro/mmfire.wav"); + //Bone Shards +// precache_sound ("necro/bonefpow.wav"); +// precache_sound ("necro/bonefnrm.wav"); +// precache_sound ("necro/bonephit.wav"); +// precache_sound ("necro/bonenhit.wav"); +// precache_sound ("necro/bonenwal.wav"); + //Raven Staff +// precache_sound ("raven/ravengo.wav"); +// precache_sound ("raven/squawk2.wav"); +// precache_sound ("raven/death.wav"); +// precache_sound ("raven/rfire1.wav"); +// precache_sound ("raven/rfire2.wav"); +// precache_sound ("raven/split.wav"); + precache_sound2 ("eidolon/roar.wav"); + precache_sound2 ("eidolon/pain.wav"); //Hurt + precache_sound2 ("eidolon/death.wav"); //Dies- long and agonizing + precache_sound2 ("eidolon/growl.wav"); // + precache_sound2 ("yakman/slam.wav"); + precache_sound2 ("yakman/grunt.wav"); + precache_sound2 ("eidolon/stomp.wav"); //Hot-steppin' +//WIN + precache_sound ("misc/winner.wav"); + precache_sound ("misc/victory.wav"); + precache_sound ("misc/smite.wav"); //Bad boy! +} + +//Succubus precache shit +void Precache_Demoness (void) +{ +//SUCCUBUS + precache_model5 ("models/h_suc.mdl"); + precache_model5 ("models/succubus.mdl"); +//Weapon 1 + precache_model5("models/sucwp1.mdl"); + precache_model5("models/sucwp1p.mdl"); + precache_model5("models/xplsn_1.spr"); +// precache_model5("models/xplsn_2.spr"); +// precache_model5("models/xplsn_3.spr"); + precache_model5("models/spark.spr"); +//Weapon 2 +// precache_model5("models/sucwp2.mdl"); + precache_model5("models/sucwp2p.mdl"); +// precache_model5("models/muzzle1.spr"); +// precache_model5("models/axplsn_1.spr"); +// precache_model5("models/axplsn_2.spr"); +// precache_model5("models/axplsn_3.spr"); +// precache_model5("models/axplsn_4.spr"); +// precache_model5("models/axplsn_5.spr"); +//Weapon 3 + precache_model5("models/sucwp3.mdl"); +// precache_model5("models/flamestr.spr"); //demoness +// precache_model5("models/pow.spr"); //demoness + precache_model5("models/firewal1.spr"); //demoness + precache_model5("models/firewal2.spr"); + precache_model5("models/firewal3.spr"); +// precache_model5("models/fboom.spr"); + precache_model5("models/firewal5.spr"); + precache_model5("models/firewal4.spr"); + +//Weapon 4 +// precache_model5("models/sucwp4.mdl"); +// precache_model5("models/lball.mdl"); +// precache_model5("models/Bluexp3.spr"); +// precache_model5 ("models/stltng2.mdl"); //Lightning- (warhammer, eidolon, lightwp) + + +//SOUNDS +//Body sounds + precache_sound5 ("succubus/fwoomp.wav"); // Slow fall + +//Weapon 1 + precache_sound5 ("succubus/brnbounce.wav"); + precache_sound5 ("succubus/brnfire.wav"); + precache_sound5 ("succubus/brnhit.wav"); + precache_sound5 ("succubus/brnwall.wav"); +//Weapon 2 +// precache_sound5 ("succubus/acidfire.wav"); +// precache_sound5 ("succubus/acidpfir.wav"); +// precache_sound5 ("succubus/acidhit.wav"); +// precache_sound5 ("succubus/blobexpl.wav"); +// precache_sound5 ("succubus/dropfizz.wav"); +//Weapon 3 + //precache_sound ("mummy/mislfire.wav"); + //precache_sound ("eidolon/flamend.wav"); + //precache_sound ("misc/fburn_bg.wav"); + //precache_sound ("death/fout.wav"); +// precache_sound5 ("succubus/firecirc.wav"); +// precache_sound5 ("succubus/flamend.wav"); +// precache_sound5 ("succubus/flamstrt.wav"); +// precache_sound5 ("succubus/flampow.wav"); + +//Weapon 4 +// precache_sound5 ("succubus/firelght.wav"); +// precache_sound5 ("succubus/firelbal.wav"); +// precache_sound5 ("succubus/firelpow.wav"); + precache_sound5 ("crusader/lghtn2.wav"); +// precache_sound5 ("succubus/buzz.wav"); +// precache_sound5 ("succubus/buzz2.wav"); +//Glyph +// precache_sound5 ("succubus/gasss.wav"); +// precache_sound5 ("succubus/hisss.wav"); +// precache_sound5 ("succubus/endhisss.wav"); + +} + + +//********************************************** +// *************** Id models +//********************************************** +void Precache_Id_mdl (void) +{ +//REMOVE!!!! + precache_model ("models/s_light.spr"); // sphere light +} + + +//********************************************** +// *************** Raven models +//********************************************** +void Precache_mdl (void) +{ +//REMOVE!!! +// precache_model("models/akarrow.mdl");//Mummy, archer, pstboar +// precache_model("models/dthball.mdl");//Goes in dthfire.hc + +//MISC + precache_model ("models/teleport.mdl"); //Teleport model + precache_model("models/xhair.mdl"); //Ballista- REPLACE!!! + precache_model ("models/spike.mdl"); +//CHUNKS + precache_model("models/shard1.mdl"); + precache_model("models/shard2.mdl"); + precache_model("models/shard3.mdl"); + precache_model("models/shard4.mdl"); + precache_model("models/shard5.mdl"); + precache_model("models/splnter1.mdl"); + precache_model("models/splnter2.mdl"); + precache_model("models/splnter3.mdl"); + precache_model("models/splnter4.mdl"); + precache_model("models/metlchk1.mdl"); + precache_model("models/metlchk2.mdl"); + precache_model("models/metlchk3.mdl"); + precache_model("models/metlchk4.mdl"); + precache_model("models/leafchk1.mdl"); + precache_model("models/leafchk2.mdl"); + precache_model("models/leafchk3.mdl"); + precache_model("models/clthchk1.mdl"); + precache_model("models/clthchk2.mdl"); + precache_model("models/clthchk3.mdl"); + precache_model("models/flesh1.mdl"); + precache_model("models/flesh2.mdl"); + precache_model("models/flesh3.mdl"); + precache_model("models/brains.mdl"); + precache_model("models/clshard1.mdl"); + precache_model("models/clshard2.mdl"); + precache_model("models/clshard3.mdl"); + precache_model("models/clshard4.mdl"); + precache_model("models/hay1.mdl"); + precache_model("models/hay2.mdl"); + precache_model("models/hay3.mdl"); + precache_model("models/shard.mdl"); //shard model for ice, rock, ashes + +//ARTIFACTS +// precache_model("models/a_shbost.mdl"); +// precache_model("models/a_hboost.mdl"); + precache_model("models/a_torch.mdl"); +// precache_model("models/a_blast.mdl"); +// precache_model("models/a_mboost.mdl"); + precache_model("models/a_telprt.mdl"); +// precache_model("models/a_tome.mdl"); +// precache_model("models/a_summon.mdl"); +// precache_model("models/a_mine.mdl"); + precache_model("models/a_glyph.mdl"); +// precache_model("models/a_haste.mdl"); +// precache_model("models/a_poly.mdl"); +// precache_model("models/a_mirror.mdl"); + precache_model("models/a_cube.mdl"); + precache_model("models/a_invinc.mdl"); +// precache_model("models/a_growth.mdl"); +// precache_model("models/a_xray.mdl"); + precache_model("models/a_invis.mdl"); + precache_model("models/cube.mdl"); +// precache_model("models/ringft.mdl"); + + //Lambinator + precache_model("models/sheep.mdl"); + precache_model("models/snout.mdl"); + //Summoning Stone + precache_model ("models/imp.mdl"); + precache_model ("models/h_imp.mdl");//empty for now + precache_model ("models/shardice.mdl"); + precache_model ("models/fireball.mdl"); + +//ITEMS + precache_model("models/i_bracer.mdl"); // Armor + precache_model("models/i_bplate.mdl"); + precache_model("models/i_helmet.mdl"); + precache_model("models/i_amulet.mdl"); +// precache_model ("models/i_gmana.mdl"); // Instant Mana +// precache_model ("models/i_bmana.mdl"); +// precache_model ("models/i_btmana.mdl"); +// precache_model ("models/i_hboost.mdl"); // Instant Health + precache_model ("models/bag.mdl"); // Our version of a backpack + +//TE_STREAM models + // TE_STREAM_SUNSTAFF1 / TE_STREAM_SUNSTAFF2 +// precache_model("models/stsunsf1.mdl"); //Sunbeam and ball models +// precache_model("models/stsunsf2.mdl"); +// precache_model("models/stsunsf3.mdl"); +// precache_model("models/stsunsf4.mdl"); +// precache_model("models/stsunsf5.mdl"); + // TE_STREAM_LIGHNING + precache_model ("models/stlghtng.mdl"); //Lightning- also warhammer + // TE_STREAM_CHAIN + precache_model("models/stchain.mdl"); //Chain- also for Scarab staff + // TE_STREAM_COLORBEAM +// precache_model("models/stclrbm.mdl"); //Colored beams of light + // TE_STREAM_ICECHUNKS +// precache_model("models/stice.mdl"); //For blizzard + // TE_STREAM_GAZE +// precache_model("models/stmedgaz.mdl"); //Medusa's gaze + // TE_STREAM_FAMINE +// precache_model("models/fambeam.mdl"); //Famine's beam attack + +//GLYPHS + precache_model("models/glyph.mdl"); //Non-artifact flagged glyph + //Paladin + precache_model ("models/blast.mdl"); //Delayed fireball + //Assassin + precache_model("models/glyphwir.mdl"); //Tripwire version of glyph + precache_model ("models/twspike.mdl"); //Trip wire spike + +//PALADIN + precache_model ("models/paladin.mdl"); + precache_model ("models/h_pal.mdl"); + //Gauntlets + precache_model("models/gauntlet.mdl"); // Paladin Weapons + //Axe + precache_model("models/axe.mdl"); + precache_model("models/axblade.mdl"); + precache_model("models/axtail.mdl"); + //Vorpal Sword + precache_model("models/vorpal.mdl"); + precache_model("models/vorpswip.mdl"); + precache_model("models/vorpshot.mdl"); + precache_model("models/vorpshok.mdl"); //Vorpal sword & lightning hit + precache_model("models/vorpshk2.mdl"); + //Purifier +// precache_model("models/purifier.mdl"); +// precache_model("models/purfir1.mdl"); //Purifier flame +// precache_model("models/drgnball.mdl"); //Purifier fireball, take 2 +// precache_model("models/ring.mdl"); //Smoke ring + +//ASSASSIN + precache_model ("models/assassin.mdl"); + precache_model ("models/h_ass.mdl"); + precache_model ("models/h_fangel.mdl");//Temp head model for Assassin + //Punch Dagger + precache_model("models/punchdgr.mdl"); + //Crossbow + precache_model("models/xbow2.mdl"); +// precache_model("models/w_l3_c4.mdl"); + precache_model("models/arrows.mdl"); + precache_model("models/crossbow.mdl"); + precache_model ("models/arrow.mdl"); + precache_model ("models/arrowhit.mdl"); + precache_model ("models/flaming.mdl"); + precache_model ("models/NFarrow.mdl"); + //Grenades + precache_model("models/v_assgr.mdl"); +// precache_model("models/assgren.mdl"); + //Scarab Staff +// precache_model("models/scarabst.mdl"); +// precache_model("models/scrbstp1.mdl"); +// precache_model("models/scrbpbdy.mdl"); +// precache_model("models/scrbpwng.mdl"); + + +//REGISTERED======================================================= + +//NECROMANCER + precache_model("models/necro.mdl"); + precache_model ("models/h_nec.mdl"); + //Sickle + precache_model("models/sickle.mdl"); // Necromancer Weapons + //Magic Missiles + precache_model("models/spllbook.mdl"); + precache_model("models/handfx.mdl"); + //Bone Shards +// precache_model("models/bonefx.mdl"); +// precache_model("models/boneshot.mdl"); +// precache_model("models/boneshrd.mdl"); +// precache_model("models/bonelump.mdl"); + //Raven Staff +// precache_model("models/ravenstf.mdl"); +// precache_model("models/vindsht1.mdl"); +// precache_model("models/ravproj.mdl"); +// precache_model("models/birdmsl2.mdl"); + +//CRUSADER + precache_model("models/crusader.mdl"); + precache_model ("models/h_cru.mdl"); + //Warhammer + precache_model("models/warhamer.mdl"); + precache_model("models/hamthrow.mdl"); + //Ice Staff + precache_model("models/icestaff.mdl"); +// precache_model("models/iceshot1.mdl"); +// precache_model("models/iceshot2.mdl"); + //Meteor Staff +// precache_model("models/meteor.mdl"); +// precache_model("models/tempmetr.mdl");//temp- meteor projectile +// precache_model("models/tornato.mdl"); +// precache_model("models/funnal.mdl"); + //Sunstaff +// precache_model("models/sunstaff.mdl"); + +//SPECIAL ABILITIES + //Necromancer + precache_model ("models/soulball.mdl");//Soul sphere + precache_model ("models/soulskul.mdl"); + //Crusader + precache_model ("models/goodsphr.mdl");//Smiting Sphere + precache_model ("models/cross.mdl"); + +// precache_model ("models/birdmisl.mdl"); +//Miscellaneous Shared + precache_model ("models/test.mdl"); //For testing + +//SIEGE + precache_model ("models/hank.mdl"); + precache_model ("models/h_hank.mdl"); + precache_model("models/ripple.mdl"); + precache_sound("misc/combust.wav"); +//Become beast + precache_model2 ("models/yakman.mdl"); + precache_model ("models/god.mdl"); //The big guy +} + + +//********************************************** +// *************** Raven sprites +//********************************************** +void Precache_spr (void) +{//ALPHABETIZED! +//FIXME: Which of these aren't being used anymore? + precache_model("models/bg_expld.spr"); + precache_model("models/bldspot1.spr"); + precache_model("models/bldspot2.spr"); + precache_model("models/bldspot3.spr"); + precache_model("models/bldspot4.spr"); + precache_model("models/bluflash.spr"); + precache_model("models/bonexpld.spr"); + precache_model("models/bspark.spr"); + precache_model("models/rcloud.spr"); + +// precache_model ("models/eidoflam.spr"); + + precache_model("models/fcircle.spr"); + precache_model("models/fl_expld.spr"); + + precache_model("models/gen_expl.spr"); +// precache_model ("models/ghost.spr"); + precache_model ("gfx/glass.spr"); + precache_model("models/grnsmk1.spr"); + precache_model ("models/gryspt.spr"); + precache_model("models/grysmk1.spr"); + precache_model ("models/gspark.spr"); + +// precache_model("models/icehit.spr"); //Ice mace shot impact + +// precache_model ("models/medhit.spr"); + precache_model ("models/mezzoref.spr"); + precache_model ("models/mm_expld.spr"); + + precache_model ("models/null.spr"); //nothing there + + precache_model("models/polymrph.spr"); + + precache_model("models/redsmk1.spr"); + precache_model ("models/redspt.spr"); + precache_model("models/rspark.spr"); + + precache_model ("gfx/s_blast.spr"); + precache_model ("models/s_bubble.spr"); // drowning bubbles + precache_model ("models/s_explod.spr"); // Not sure, but it was in our directory + precache_model ("models/s_light.spr"); + precache_model("models/sm_blue.spr"); + precache_model("models/sm_expld.spr"); + precache_model("models/sm_white.spr"); + precache_model("gfx/smoke1.spr"); + precache_model("models/spark.spr"); + precache_model("models/spark0.spr"); + precache_model ("gfx/stone.spr"); + + precache_model("models/telesmk1.spr"); + precache_model("models/telesmk2.spr"); + precache_model("models/telesmk3.spr"); + + precache_model("models/whtsmk1.spr"); + precache_model("models/wsplash.spr"); + + precache_model("models/xbowexpl.spr"); //Crossbow explosion +// precache_model("models/xplod29.spr"); //old Eidolon flames + precache_model("models/xpspblue.spr"); + + precache_model("models/yr_flsh.spr"); + precache_model3("models/rcloud.spr"); +} + +void precache_archer() +{ + precache_model("models/archer.mdl"); + precache_model("models/archerhd.mdl"); + + precache_model("models/gspark.spr"); + + precache_sound ("archer/arrowg.wav"); + precache_sound ("archer/arrowr.wav"); + + precache_sound ("archer/growl.wav"); + precache_sound ("archer/pain.wav"); + precache_sound ("archer/sight.wav"); + precache_sound ("archer/death.wav"); + precache_sound ("archer/draw.wav"); +} + +void precache_spider () +{ + precache_model("models/spider.mdl"); + precache_model("models/sflesh1.mdl"); + precache_model("models/sflesh2.mdl"); + precache_model("models/sflesh3.mdl"); + + precache_sound("spider/bite.wav"); + precache_sound("spider/pain.wav"); + precache_sound("spider/death.wav"); + precache_sound("spider/step1.wav"); + precache_sound("spider/step2.wav"); + precache_sound("spider/step3.wav"); +} + +void Precache_hw(void) +{ + // Maps + precache_file5("maps/hwdm1.bsp"); + precache_file5("maps/hwdm2.bsp"); + precache_file5("maps/hwdm3.bsp"); + precache_file5("maps/hwdm4.bsp"); + precache_file5("maps/hwdm5.bsp"); + +// precache_sound5 ("crusader/sunhuml.wav"); //Looping sunhum +// precache_sound5 ("misc/cubehum.wav"); //force cube +// precache_sound5 ("misc/Beep1.wav"); //force cube +// precache_sound5 ("misc/pulsel.wav"); //Fully charged staff- loops +// precache_sound5 ("golem/gbfire.wav"); + + // Models + precache_model5("models/assgren.mdl"); + precache_model5("models/newmmis.mdl"); + precache_model5 ("models/fstep.mdl"); //For testing + + precache_file5("sound/misc/talk.wav"); + + // Taunts don't need to be precached as sounds + precache_file5("sound/taunt/taunt001.wav"); + precache_file5("sound/taunt/taunt002.wav"); + precache_file5("sound/taunt/taunt003.wav"); + precache_file5("sound/taunt/taunt004.wav"); + precache_file5("sound/taunt/taunt005.wav"); + precache_file5("sound/taunt/taunt006.wav"); + precache_file5("sound/taunt/taunt007.wav"); +// precache_file5("sound/taunt/taunt008.wav"); + precache_file5("sound/taunt/taunt009.wav"); + precache_file5("sound/taunt/taunt010.wav"); + precache_file5("sound/taunt/taunt011.wav"); +// precache_file5("sound/taunt/taunt012.wav"); + precache_file5("sound/taunt/taunt013.wav"); + precache_file5("sound/taunt/taunt014.wav"); + precache_file5("sound/taunt/taunt015.wav"); + precache_file5("sound/taunt/taunt016.wav"); + precache_file5("sound/taunt/taunt017.wav"); + precache_file5("sound/taunt/taunt018.wav"); + precache_file5("sound/taunt/taunt019.wav"); + precache_file5("sound/taunt/taunt020.wav"); +// precache_file5("sound/taunt/taunt021.wav"); +// precache_file5("sound/taunt/taunt022.wav"); +// precache_file5("sound/taunt/taunt023.wav"); + precache_file5("sound/taunt/taunt024.wav"); + precache_file5("sound/taunt/taunt025.wav"); + precache_file5("sound/taunt/taunt026.wav"); + precache_file5("sound/taunt/taunt027.wav"); + precache_file5("sound/taunt/taunt028.wav"); +// precache_file5("sound/taunt/taunt029.wav"); + precache_file5("sound/taunt/taunt030.wav"); + precache_file5("sound/taunt/taunt031.wav"); + precache_file5("sound/taunt/taunt032.wav"); + precache_file5("sound/taunt/taunt033.wav"); + precache_file5("sound/taunt/taunt034.wav"); + precache_file5("sound/taunt/taunt035.wav"); + precache_file5("sound/taunt/taunt036.wav"); + + // misc + precache_file5 ("gfx/menu/conchars.lmp"); +} + diff --git a/progs.src b/progs.src new file mode 100644 index 0000000..b6af63a --- /dev/null +++ b/progs.src @@ -0,0 +1,143 @@ + +/* + * $Header$ + */ + +hwprogs.dat + +global.hc +entity.hc +constant.hc +builtin.hc +proto.hc + +math.hc +strings.hc +spawn.hc +chunk.hc + +sound.hc +fx.hc +plaque.hc +camera.hc + +subs.hc +fight.hc +path.hc +ai.hc +//spawner.hc +projbhvr.hc // Miscellaneous Projectile Behaviour(homing, spiral, spread, etc) +ravenai.hc +MG_AI.hc //New AI routines +waypoint.hc +altdeath.hc +damage.hc +combat.hc +siege.hc + +artifact.hc // Artifacts, items, and rings +items.hc +//cube.hc +newcube.hc +invntory.hc +rings.hc +wp_art.hc + +// Objects +object.hc +barrel.hc +light.hc +lightning.hc +breakabl.hc +soul.hc +spells.hc + +explode.hc //explosions, weapons.hc was checked out + +gauntlet.hc // Paladin Weapons +vorpal.hc +axe.hc +//purifier.hc + +warhamer.hc // Crusader weapons +icemace.hc +//meteor.hc +//sunstaff.hc + +sickle.hc // Necromancer weapons +magicmis.hc +//boner.hc +//ravenstf.hc + +punchdgr.hc // Assassin weapons +assgren.hc +crossbow.hc +//setstaff.hc + +bldrain.hc +//acidorb.hc +flameorb.hc +//lightwp.hc // Succubus Weapons + +weapons.hc +tripmine.hc // UQ tripmines + +impulse.hc +weather.hc + +precache.hc +world.hc +head.hc +corpse.hc +allplay.hc +specials.hc +dmlevels.hc +client.hc +spectate.hc +monsters.hc +doors.hc +buttons.hc +triggers.hc +cat2.hc +quake.hc +plats.hc +plats_mp.hc +misc.hc +torch.hc + +newplay.hc +setmodth.hc + +fish.hc +sheep.hc +//raven.hc +rat.hc +//snake.hc + +fireball.hc // Imp stuff +shardice.hc +//mummy.hc +imp.hc +//spider.hc +//scorpion.hc +//golem.hc +//skullwiz.hc +//medusa.hc +mezzoman.hc +//archer.hc +spit.hc // Hydra stuff +//hydra.hc +//faspell.hc // Fallen angel stuff +//fablade.hc +//fangel.hc + +eric.hc + +//rider.hc +//pstboar.hc +//famhorse.hc +//warhorse.hc +//dthhorse.hc +//eidolon.hc + +stats.hc diff --git a/projbhvr.hc b/projbhvr.hc new file mode 100644 index 0000000..176624f --- /dev/null +++ b/projbhvr.hc @@ -0,0 +1,519 @@ +/* +==================================================================== +PROJBHVR.HC +Projectile Behaviours +By Michael Gummelt + +Various routines for projectile behaviours. +=================================================================== +*/ +void(float num_bubbles) DeathBubbles; + +/* +==================================================== +void Skip() +MG +Returns True if the projectile hit a surface at +a slight enough angle to deflect. False if not +(meaning the missile should be destroyed in +the touch function this was called from). +The missile must be a MOVETYPE_BOUNCEMISSILE for +this to work, and it's o_angle must match it's +last known velocity. For now the angle of +deflection is anything below the 0.2 (using the dot +product of the negative value of the o_angle +and the trace_plane_normal of the surface it +hit.) But this could be easily customized to +use a parameter or entity field. +Values Used: .o_angle (.movetype must be + MOVETYPE_BOUNCEMISSILE) +===================================================== +*/ +float Skip (void) +{ + vector dir1,dir2; + float dot; + dir1 = normalize(self.velocity); + traceline(self.origin-dir1*4,self.origin+dir1*16,TRUE,self); + dir2=trace_plane_normal; + dir1*=-1; + dot=dir1*dir2; + + if(dot<=0.15&&trace_fraction<1) + return TRUE; + else + return FALSE; +} + +/* +==================================================== +void Veer(float amount) +MG +This function will make a projectile +wander from it's course in a random +manner. It does not actually directly +use the .veer value, you must send the +veer amount value to the function as +a parameter. But this allows it to +be used in other ways (call it once, +etc.) So you can call it by using +Veer(self.veer) or Veer(random()*300) +or Veer([any number]), etc. +===================================================== +*/ +void Veer(float amount) +{ +//useful code for making projectiles wander randomly to a specified degree +vector veerdir; + veerdir_x=veerdir_y=veerdir_z=amount; + self.velocity+=RandomVector(veerdir); + self.angles=vectoangles(self.velocity); +} + +void VeerThink () +{ + Veer(self.veer); + if(self.think==Veer) + thinktime self : 0.1; +} + +/* +========================================================= +float ahead (entity loser, entity from) +MG + +Checks to see if "loser" is within the forward cone +(based on facing, NOT velocity!) of "from". +Cone size defaults to 0.2 unless crossbow arrows (they +do a one-time narrow-cone aquisition of 0.8) + +NOTE: "accept" can be a value between -1 and 1, the + higher the value, the smaller the cone. + +Returns TRUE if so, FALSE if not. +========================================================= +*/ +float ahead (entity loser, entity from) +{ +vector proj_dir, spot1, spot2, vec; +float accept, dot; + + proj_dir=normalize(from.velocity); + + spot1 = from.origin; + spot2 = (loser.absmin+loser.absmax)*0.5; + + if(from.classname=="flaming arrow"||from.classname=="bolt") + accept=0.875; + else + accept=0.2; + + vec = normalize (spot2 - spot1); + dot = vec * proj_dir; + + if ( dot > accept) + return TRUE; + + return FALSE; +} + +/* +========================================================= +float heading (entity loser, entity from, float accept) +MG + +Checks to see if "loser" is within the forward cone +(based on velocity, NOT facing!) of "from". + +"accept" is the size of the cone (see "ahead"), which, +if none is sent, defaults to 0.8 (rather narrow). + +Returns TRUE if so, FALSE if not. +========================================================= +*/ +float heading (entity loser, entity from, float accept) +{ +vector proj_dir, spot1, spot2, vec; +float dot; + + proj_dir=normalize(from.velocity); + + spot1 = from.origin; + spot2 = (loser.absmin+loser.absmax)*0.5; + + if(!accept) + accept=0.8; + + vec = normalize (spot2 - spot1); + dot = vec * proj_dir; + + if ( dot > accept) + return TRUE; + + return FALSE; +} + +void()HomeThink; +/* +====================================== +entity HomeFindTarget() +MG +Simply looks for and returns a target +to go after. +====================================== +*/ +entity HomeFindTarget() +{ +entity loser; +float dist, bestdist; + + if(self.think!=HomeThink)//one-time only acquisition + bestdist=5000; + else + bestdist=1000; + loser=findradius(self.origin,bestdist); + bestdist+=1; + while (loser) + { + if(loser.health&&loser.takedamage&&(loser.flags2&FL_ALIVE)&&visible(loser)&&loser!=self&&loser!=world&&loser!=self.owner&&!loser.effects&EF_NODRAW)//&&!(loser.artifact_active&ARTFLAG_STONED) Why Not? + { + if((!self.aflag||self.ideal_yaw)&&!ahead(loser,self)) //looks for someone in front first time + dprint("");//not infront\n"); + else if(teamplay&&loser.classname=="player"&&((loser.team==self.owner.team&&self.owner.classname=="player")||(loser.team==self.controller.team&&self.owner.classname=="player"))) + dprint("");//targeting teammate\n"); + else if(coop&&loser.classname=="player"&&(self.owner.classname=="player"||self.controller.classname=="player")) + dprint("");//target coop player\n"); + else if((self.classname=="flame arrow"||self.classname=="bolt")&&deathmatch&&vlen(loser.velocity)>300) + dprint("");//DM: player moving too fast\n"); + else if(loser.controller==self.owner&&self.owner.classname=="player")//don't home in on owner's imps + dprint("");//owner's thing\n"); + else + { + //make it wait for closest (by vlen) or just go for first found? + dist=vlen(self.origin-loser.origin); + if(dist150) + { + 8; +// dprint("");//DM: player moving too fast\n"); + } + else if((who.classname=="chainball")&&!ahead(loser,who))//only look ahead if yer the scarab staff + { + 8; +// dprint("");//not infront\n"); + } + else if(loser.controller==who.owner&&who.owner.classname=="player")//don't home in on owner's imps + { + 8; +// dprint("");//owner's thing\n"); + } + else + { + //make it wait for closest (by vlen) or just go for first found? + dist=vlen(who.origin-loser.origin); + if(dist=PB_STAGE_CHARGE&&self.monster_stage=PB_STAGE_CHARGE&&self.monster_stagetime) + { + if(!walkmove(self.angles_y,self.speed,TRUE)) + { + if (trace_ent!=world&&trace_ent.takedamage&&self.torchtime30) + { + self.monster_stage=PB_STAGE_BACKUP; + self.aflag=0; + self.turn_time=time+3;//Back up for 3 secs + } + if(self.aflag) + { + makevectors(self.angles); + tracearea(self.origin,self.origin+v_forward*200,'-48 -48 0','48 48 100',TRUE,self); + if(trace_plane_normal!='0 0 0') + self.ideal_yaw=vectoyaw((trace_plane_normal+v_forward)*0.5); + navigate(fabs(self.speed)); + } + ChangeYaw(); + } + + if ((!self.enemy) || (self.enemy.health <= 0)) + { + if(self.enemy) + sound(self,CHAN_VOICE,"pest/laugh.wav",1,ATTN_NONE); + + if (!FindTarget(TRUE)) + { + self.enemy = world; + if(!self.monster_awake) + self.monster_stage = self.rider_gallop_mode = PB_STAGE_STAND; + } + else + sound(self,CHAN_VOICE,"pest/sight.wav",1,ATTN_NONE); + self.goalentity = self.enemy; + } + else + self.monster_awake=TRUE; + + enemy_vis=visible(self.enemy); + if(enemy_vis) + self.search_time=time+5-coop*2; + + if(self.rider_gallop_modeself.angles_y+89&&self.movechain.ideal_yawself.angles_y - 180) + self.movechain.ideal_yaw=self.angles_y - 89; + } + else + self.movechain.ideal_yaw=self.angles_y; + oself=self; + self=self.movechain; + ChangeYaw(); + self=oself; + + if(self.rider_gallop_mode==PB_STAGE_ATTACK||self.rider_gallop_mode==PB_STAGE_ATTACK2) + self.movechain.frame+=1; + else if(self.rider_gallop_mode= $Parrow6) + if(self.monster_stage==PB_STAGE_BACKUP) + self.rider_gallop_mode=PB_STAGE_NORMAL; + else + self.rider_gallop_mode=self.monster_stage; + } + else if(self.rider_gallop_mode == PB_STAGE_ATTACK2) + { + if (self.movechain.frame == $Phive33) + throw_hive(); + + if (self.movechain.frame >= $Phive38) + if(self.monster_stage==PB_STAGE_BACKUP) + self.rider_gallop_mode=PB_STAGE_NORMAL; + else + self.rider_gallop_mode=self.monster_stage; + } + + if(self.monster_stage >= PB_STAGE_CHARGE&&self.monster_stage=random(20,40)) + { + self.movechain.frame=$PtranD1; + self.monster_stage=self.rider_gallop_mode=PB_STAGE_CHARGE_END; + } + } + if(self.frame==$BtranD8) + { + self.lifespan=time + 5; + self.monster_stage = self.rider_gallop_mode=PB_STAGE_NORMAL; + self.yaw_speed=4; + } + if(self.rider_gallop_mode==PB_STAGE_CHARGE) + { + if(random(1000)<=5) + { + enemy_infront=infront_of_ent(self.enemy,self.movechain); + if(enemy_vis&&(enemy_infront||random()<0.2)) + if (random()<0.1&&self.cnt<=0) // Shoot + { + self.rider_gallop_mode = PB_STAGE_ATTACK2; + self.movechain.frame = $Phive1; + } + else + { + self.rider_gallop_mode = PB_STAGE_ATTACK; + self.movechain.frame = $Parrow1; + } + } + } + } + + if (fabs(pst_speed[self.monster_stage] - fabs(self.speed)) < 0.2) + self.speed = pst_speed[self.monster_stage]; + else if (pst_speed[self.monster_stage] > fabs(self.speed)) + self.speed = fabs(self.speed)+0.2; + else + self.speed=fabs(self.speed) - 0.2; + + if(self.monster_stage==PB_STAGE_BACKUP) + if(self.turn_timetime) + chance/=3; + + if(random(100)<3) + sound(self,CHAN_VOICE,"pest/laugh.wav",1,ATTN_NONE); + + if (chance < 3&&self.cnt<=0) // Shoot + { + self.rider_gallop_mode = PB_STAGE_ATTACK2; + self.movechain.frame = $Phive1; + } + else if(chance < 5) // Shoot + { + self.rider_gallop_mode = PB_STAGE_ATTACK; + self.movechain.frame = $Parrow1; + } + else if(chance < 8&&self.monster_stage self.speed) + self.speed += 0.2; + else + self.speed -= 0.2; +} + + + + + + + +void rider_death(); + +/*QUAKED rider_famine (1 0 0) (0 0 0) (50 50 50) +Famine rider monster. You must place rider_path entites +on the map. The rider will first proceed to the +rider_path point with a path_id of 1. +-------------------------FIELDS------------------------- +-------------------------------------------------------- + +*/ +void() rider_famine = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model2 ("models/boss/famhorse.mdl"); + precache_model2 ("models/boss/famrider.mdl"); + precache_model2 ("models/boss/shaft.mdl"); + precache_model2 ("models/boss/circle.mdl"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.yaw_speed = 2; + + setmodel (self, "models/boss/famhorse.mdl"); + self.skin = 0; + + setsize (self, '-55 -55 0', '55 55 100'); + self.health = 1; + self.takedamage=DAMAGE_YES; + self.rider_gallop_mode = 0; + self.speed = fam_speed[self.rider_gallop_mode]; + self.rider_path_distance = 200; + self.monster_stage = FH_STAGE_NORMAL; + self.mass = 30000; + + create_famrider(self); + + self.th_die = rider_die; + self.think = famhorse_move; + self.nextthink = time + 0.2; // wait for path points to spawn + +// warhorse_die(); +}; + diff --git a/punchdgr.hc b/punchdgr.hc new file mode 100644 index 0000000..e183961 --- /dev/null +++ b/punchdgr.hc @@ -0,0 +1,379 @@ +/* + * $Header: /HexenWorld/Siege/punchdgr.hc 17 6/01/98 2:49a Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\pnchdagr\final\punchdgr.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\pnchdagr\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// Frame 1 +$frame rootdag +// +// Frame 2 - 9 +$frame attacka1 attacka3 +$frame attacka7 +$frame attacka12 attacka13 attacka15 +$frame attacka16 attacka19 + +// Frame 10 - 21 +$frame attackb5 +$frame attackb6 attackb7 +$frame attackb16 attackb17 attackb18 attackb19 attackb20 +$frame attackb25 +$frame attackb26 attackb27 attackb29 + +// Frame 22 - 33 +$frame attackc3 attackc4 attackc5 +$frame attackc6 attackc7 +$frame attackc11 attackc12 attackc13 +$frame attackc16 attackc18 attackc19 attackc20 + +// Frame 34 - +$frame attackd2 attackd4 attackd5 +$frame attackd6 attackd10 +$frame attackd11 attackd13 attackd14 attackd15 +$frame attackd16 attackd17 attackd20 attackd21 + +$frame f1 f2 f3 f4 f5 f6 f7 f8 + + +// Frame Code +void() Ass_Pdgr_Fire; +void punchdagger_swipeitem (entity robber, entity robbee); + + +void fire_punchdagger () +{ + vector source; + vector org,dir; + float damg, inertia; + float damage_mod; + float damage_base; + float backstab; + + damage_mod = 10; + + makevectors (self.v_angle); + source = self.origin + self.proj_ofs; + + if (self.artifact_active & ART_TOMEOFPOWER) + traceline (source, source + v_forward*96, FALSE, self); + else + traceline (source, source + v_forward*64, FALSE, self); + + if (trace_fraction == 1.0) + { + traceline (source, source + v_forward*64 - (v_up * 30), FALSE, self); // 30 down + if (trace_fraction == 1.0) + { + traceline (source, source + v_forward*64 + v_up * 30, FALSE, self); // 30 up + if (trace_fraction == 1.0) + return; + } + } + + org = trace_endpos + (v_forward * 4); + + if (trace_ent.takedamage) + { + + //FIXME:Add multiplier for level and strength + if(trace_ent.flags2&FL_ALIVE&&self.playerclass==CLASS_ASSASSIN)//!fov(self,trace_ent,90) + { + vector t_vf,m_vf; + makevectors(trace_ent.angles); + t_vf = v_forward; + makevectors(self.angles); + m_vf = v_forward; + makevectors(self.v_angle); + if(t_vf*m_vf>0.5)//facing generally the same direction + { + CreateRedFlash(trace_endpos); + damage_base=random(50,100); + backstab=TRUE; + } + } + else + { + damage_base = WEAPON1_BASE_DAMAGE; + damage_mod = WEAPON1_ADD_DAMAGE; + } + + damg = random(damage_mod + damage_base,damage_base); + SpawnPuff (org, '0 0 0', damg,trace_ent); + T_Damage (trace_ent, self, self, damg); + + if (!MetalHitSound(trace_ent.thingtype)) + sound (self, CHAN_WEAPON, "weapons/slash.wav", 1, ATTN_NORM); + + if(backstab) + { + if(!trace_ent.flags2&FL_ALIVE) + { + centerprint(self,"Critical Hit Backstab!\n"); + } + else + { + centerprint(self,"Backstab!\n"); + } + } + } + else + { // hit wall + if (!MetalHitSound(trace_ent.thingtype)) + sound (self, CHAN_WEAPON, "weapons/hitwall.wav", 1, ATTN_NORM); + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_GUNSHOT); + WriteByte (MSG_BROADCAST, 1); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + + if (self.artifact_active & ART_TOMEOFPOWER) + CreateWhiteFlash(org); + else + { + org = trace_endpos + (v_forward * -1) + (v_right * 15); + org -= '0 0 26'; + CreateSpark (org); + } + } +} + +void punchdagger_idle(void) +{ + self.th_weapon=punchdagger_idle; + self.weaponframe=$rootdag; +} + +void punchfwd (float progress) +{ +// vector source,myangle; + + if (!(self.artifact_active & ART_TOMEOFPOWER)) + return; +/* + myangle = self.v_angle; + myangle_x = 0; + makevectors (myangle); + source = self.origin + self.proj_ofs; + + traceline (source, source + v_forward*96, FALSE, self); + + progress = progress *2; + if (progress > 1) + progress = 2-progress; + self.velocity = self.velocity + v_forward*500*(progress + 0.2)*trace_fraction; + */ +} + +void punchbk (float progress) +{ + if (!(self.artifact_active & ART_TOMEOFPOWER)) + return; +/* + progress = progress *2; + if (progress > 1) + progress = 2-progress; + makevectors(self.angles); +// self.velocity = self.velocity - v_forward*500*(progress + 0.2); + self.velocity = self.velocity - v_forward*250*(progress + 0.2); +*/ +} + +void () punchdagger_d = +{ + self.th_weapon=punchdagger_d; + self.wfs = advanceweaponframe($attackd2,$attackd21); + + if ((self.weaponframe >= $attackd4)&&(self.weaponframe < $attackd10)) + { + punchfwd((self.weaponframe - $attackd4)/($attackd10 - $attackd4)); + } + + if ((self.weaponframe >= $attackd11)&&(self.weaponframe < $attackd15)) + { + punchbk(1-(self.weaponframe - $attackd11)/($attackd15 - $attackd11)); + } + + if (self.weaponframe == $attackd5) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + + if (self.weaponframe == $attackd10) + fire_punchdagger(); + + if(self.wfs==WF_CYCLE_WRAPPED) + punchdagger_idle(); +}; + + +void () punchdagger_c = +{ + self.th_weapon=punchdagger_c; + self.wfs = advanceweaponframe($attackc3,$attackc20); + + if ((self.weaponframe >= $attackc4)&&(self.weaponframe < $attackc7)) + { + punchfwd((self.weaponframe - $attackc4)/($attackc7 - $attackc4)); + } + + if ((self.weaponframe >= $attackc11)&&(self.weaponframe < $attackc16)) + { + punchbk(1-(self.weaponframe - $attackc11)/($attackc16 - $attackc11)); + } + +// if (self.weaponframe == $attackc7) +// sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + +// if (self.weaponframe == $attackc11) +// fire_punchdagger(); + + if (self.weaponframe == $attackc6) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + + if (self.weaponframe == $attackc7) + fire_punchdagger(); + + if(self.wfs==WF_CYCLE_WRAPPED) + punchdagger_idle(); +}; + +void () punchdagger_b = +{ + self.th_weapon=punchdagger_b; + self.wfs = advanceweaponframe($attackb5,$attackb29); + + if ((self.weaponframe >= $attackb6)&&(self.weaponframe < $attackb17)) + { + punchfwd((self.weaponframe - $attackb6)/($attackb17 - $attackb6)); + } + + if ((self.weaponframe >= $attackb18)&&(self.weaponframe < $attackb25)) + { + punchbk(1-(self.weaponframe - $attackb18)/($attackb25 - $attackb18)); + } + + if (self.weaponframe == $attackb6) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + + if (self.weaponframe == $attackb17) + fire_punchdagger(); + + if(self.wfs==WF_CYCLE_WRAPPED) + punchdagger_idle(); +}; + +void () punchdagger_a = +{ + self.th_weapon=punchdagger_a; + self.wfs = advanceweaponframe($attacka1,$attacka19); + + if ((self.weaponframe >= $attacka3)&&(self.weaponframe < $attacka13)) + { + punchfwd((self.weaponframe - $attacka3)/($attacka13 - $attacka3)); + } + + if ((self.weaponframe >= $attacka15)&&(self.weaponframe < $attackb5)) + { + punchbk(1-(self.weaponframe - $attacka15)/($attackb5 - $attacka15)); + } + + if (self.weaponframe == $attacka7) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + + if (self.weaponframe == $attacka13) + fire_punchdagger(); + + if(self.wfs==WF_CYCLE_WRAPPED) + punchdagger_idle(); +}; + +float r2; + + +void Ass_Pdgr_Fire (void) +{ + if (!(self.artifact_active & ART_TOMEOFPOWER)) + self.attack_finished = time + 0.7; // Attack every .7 seconds normally + else + self.attack_finished = time + 1.0; // Attack every 1.5 seconds tomed--prevent tome flyers as best we can + if (r2==1) + punchdagger_a(); + else if (r2==2) + punchdagger_b(); + else if (r2==3) + punchdagger_c(); + else + punchdagger_d(); + r2+=1; + if (r2>4) + r2=1; +} + +void punchdagger_select (void) +{ + self.th_weapon=punchdagger_select; + self.wfs = advanceweaponframe($f8,$f1); + self.weaponmodel = "models/punchdgr.mdl"; + if(self.wfs==WF_CYCLE_STARTED) + sound(self,CHAN_WEAPON,"weapons/unsheath.wav",1,ATTN_NORM); + if(self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + punchdagger_idle(); + } +} + +void punchdagger_deselect (void) +{ + self.th_weapon=punchdagger_deselect; + self.wfs = advanceweaponframe($f1,$f8); + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); + +} + +void punchdagger_swipeitem (entity robber, entity robbee) +{ + float numTries,swiped,tempSwipe,low,high; + + if (robber.classname != "player") + return; + if (robbee.classname != "player") + return; + + numTries = 0; + swiped = 0; + low = STR_TORCH; +// low = low-0.3; + high = STR_RINGFLIGHT; +// high = high+0.3; + + while (!swiped && (numTries < 15)) + { + numTries+=1; + tempSwipe = rint(random(low,high)); + if (getInventoryCount(robbee,tempSwipe)>0 && roomForItem(robber,tempSwipe) > 0 && + ((tempSwipe != STR_INVINCIBILITY)||(dmMode != DM_CAPTURE_THE_TOKEN)))//don't steal the icon in capture the icon + { + swiped = tempSwipe; + adjustInventoryCount(robber, swiped, 1); + adjustInventoryCount(robbee, swiped, -1); + centerprint2(robber, "You Stole ", getstring(swiped)); + centerprint2(robbee, getstring(swiped), " Stolen From You!"); + } + } + +} + diff --git a/purifier.hc b/purifier.hc new file mode 100644 index 0000000..6fd9d55 --- /dev/null +++ b/purifier.hc @@ -0,0 +1,433 @@ +/* + * $Header: /HexenWorld/Siege/purifier.hc 14 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\purifier\final\purifier.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\purifier\final +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame Rootpose +// +$frame 1Lshot1 1Lshot2 1Lshot3 + +// +$frame 1Rshot1 1Rshot2 1Rshot3 + +// +$frame 2Lshot1 2Lshot2 2Lshot3 + +// +$frame 2Rshot1 2Rshot2 2Rshot3 + +// +$frame 3Rshot1 3Rshot2 3Rshot3 + +// +$frame bigshot1 bigshot2 bigshot3 bigshot4 bigshot5 +$frame bigshot6 bigshot7 bigshot8 bigshot9 + +// +$frame select1 select2 select3 select4 select5 +$frame select6 select7 select8 select9 select10 +$frame select11 select12 + + +//================================================================== + + +void purifier_ready (void); + +void pmissile_gone(void) +{ + stopSound(self,0); + //sound (self, CHAN_VOICE, "misc/null.wav", 1, ATTN_NORM); + //sound (self, CHAN_WEAPON, "misc/null.wav", 1, ATTN_NORM); + remove(self); +} + +/* +============ +pmissile2_touch - missile2 hit something. Hurt it bad +============ +*/ +void pmissile2_touch (void) +{ + float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + pmissile_gone(); + return; + } + + // don't do radius damage to the other, because all the damage + // was done in the impact + //damg = random(150,200); + damg = random(60,110); + if (other.health) + { + T_Damage (other, self, self.owner, damg ); + if((other.flags&FL_CLIENT||other.flags&FL_MONSTER)&&other.mass<200) + { + vector hitdir; + + hitdir=self.movedir*300; + hitdir_z+=150; + if(hitdir_z<0) + hitdir_z=0; + other.velocity=hitdir; + other.flags(-)FL_ONGROUND; + } + } + + damg = random(120,160); + T_RadiusDamage (self, self.owner, damg, other); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_PURIFY2_EXPLODE); + WriteCoord (MSG_MULTICAST, self.origin_x - self.movedir_x * 8); + WriteCoord (MSG_MULTICAST, self.origin_y - self.movedir_y * 8); + WriteCoord (MSG_MULTICAST, self.origin_z - self.movedir_z * 8); + multicast(self.origin,MULTICAST_PHS_R); + + remove(self); +} + +/* +============ +pmissile2_puff - create smoke ring behind missile +============ +*/ +void pmissile2_puff(void) +{ + self.nextthink = time + .3; + self.think = pmissile2_puff; + + if(time>self.lifetime - 1.7) //Don't start tracking until it's been in the world 1/3 of a second + { + HomeThink(); + self.angles=vectoangles(self.velocity); + } + + if (self.lifetime < time) // Kill missile if it's time is up + pmissile_gone(); + + self.movedir = normalize(self.velocity); + self.angles = vectoangles(self.movedir); + + // 300 is how far this thing travels in .3 seconds... + traceline(self.origin, self.origin + self.movedir * 300.0, FALSE, self); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_PURIFY2_MISSILE); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + WriteByte (MSG_MULTICAST, self.angles_y*256.0/360.0); + WriteByte (MSG_MULTICAST, self.angles_x*256.0/360.0); + WriteByte (MSG_MULTICAST, trace_fraction * 100); + multicast(self.origin,MULTICAST_PVS); +} + +/* +============ +launch_pmissile2 - create and launch power up missile +============ +*/ +void launch_pmissile2 (void) +{ + local entity missile; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.frags=TRUE; + + missile.classname = "purimissile"; + + // set missile speed + makevectors (self.v_angle); + missile.velocity = normalize(v_forward); + missile.velocity = missile.velocity * 1000; + + missile.touch = pmissile2_touch; + missile.angles = vectoangles(missile.velocity); + + //sound (self, CHAN_VOICE, "paladin/purfireb.wav", 1, ATTN_NORM); + weapon_sound(self, "paladin/purfireb.wav"); + + setmodel (missile, "models/drgnball.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + + setorigin (missile, self.origin + v_forward*10 + v_right * 1 + v_up * 40); + + missile.effects=EF_BRIGHTLIGHT; + missile.nextthink = time + .3; + missile.think = pmissile2_puff; + missile.lifetime = time + 2; +//Homing stuff------------------- + missile.veer=FALSE; //No random wandering + missile.turn_time=3;//Lower the number, tighter the turn + missile.speed=1000; //Speed + missile.ideal_yaw=TRUE;//Only track things in front +//End homing stuff------------------- + self.greenmana -= 8; + self.bluemana -= 8; + + //missile.effects(+)EF_PURIFY2_EFFECT; + missile.effects(+)EF_NODRAW; + + entity oldself; + oldself = self; + self = missile; + + missile.think(); + + self = oldself; +} + + +/* +============ +purifier_tomefire - firing animation when in power up mode +============ +*/ +void purifier_tomefire (void) +{ + self.wfs = advanceweaponframe($bigshot1,$bigshot9); + self.th_weapon=purifier_tomefire; + if(self.weaponframe==$bigshot2) + { + self.punchangle_x= -4; + launch_pmissile2 (); + if(self.classname=="player") + { + self.velocity+=normalize(v_forward)*-200;//include mass + self.flags(-)FL_ONGROUND; + } + self.attack_finished = time + 1.0; + } + else if(self.wfs==WF_CYCLE_WRAPPED) + purifier_ready(); +} + +/* +============ +launch_pmissile1 - create and launch normal missile +============ +*/ +void launch_pmissile1 (void) +{ + vector startSpot; + float damg; + + makevectors (self.v_angle); + + startSpot = self.origin + self.proj_ofs + v_forward * 6; + + if ((self.cnt==1) || (self.cnt==3)) + { + startSpot += v_right * 10; + } + else if ((self.cnt==0) || (self.cnt==2)) + { + startSpot -= v_right * 10; + } + + traceline(startSpot, startSpot + v_forward * 2000, FALSE, self); + + damg = random(8,16); + if (trace_ent.health) + { + T_Damage (trace_ent, self, self, damg ); + } + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_PURIFY1_EFFECT); + WriteCoord (MSG_MULTICAST, startSpot_x); + WriteCoord (MSG_MULTICAST, startSpot_y); + WriteCoord (MSG_MULTICAST, startSpot_z); + WriteByte (MSG_MULTICAST, (self.v_angle_y/360.0)*256.0); + WriteByte (MSG_MULTICAST, (self.v_angle_x/360.0)*-256.0); + WriteShort(MSG_MULTICAST, (trace_fraction * 2000)); + multicast(self.origin,MULTICAST_PVS); + + self.greenmana -= 1; + self.bluemana -= 1; + + self.cnt += 1; + + if (self.cnt > 3) + { + self.cnt =0; + } +} + +/* +============ +purifier_rapidfire? - different rapid fire animations +============ +*/ +void purifier_rapidfire2R (void) +{ + self.wfs = advanceweaponframe($2Rshot1,$2Rshot3); + self.th_weapon=purifier_rapidfire2R; + + if (self.weaponframe == $2Rshot3) + self.punchangle_x= random(-3); + + if (self.attack_finished <= time&&self.button0) + launch_pmissile1(); + + if (self.wfs==WF_CYCLE_WRAPPED) + purifier_ready(); +} + +void purifier_rapidfire2L (void) +{ + self.wfs = advanceweaponframe($2Lshot1,$2Lshot3); + self.th_weapon=purifier_rapidfire2L; + + if (self.weaponframe == $1Lshot3) + self.punchangle_x= random(-3); + + if (self.attack_finished <= time&&self.button0) + launch_pmissile1(); + + if (self.wfs==WF_CYCLE_WRAPPED) + purifier_ready(); +} + +void purifier_rapidfire1R (void) +{ + self.wfs = advanceweaponframe($1Rshot1,$1Rshot3); + self.th_weapon=purifier_rapidfire1R; + + if (self.weaponframe == $1Rshot3) + self.punchangle_x= random(-3); + + if (self.attack_finished <= time&&self.button0) + launch_pmissile1(); + + if (self.wfs==WF_CYCLE_WRAPPED) + purifier_ready(); +} + +void purifier_rapidfire1L (void) +{ + self.wfs = advanceweaponframe($1Lshot1,$1Lshot3); + self.th_weapon=purifier_rapidfire1L; + + if (self.weaponframe == $1Lshot3) + self.punchangle_x= random(-3); + + if (self.attack_finished <= time&&self.button0) + launch_pmissile1(); + + if (self.wfs==WF_CYCLE_WRAPPED) + purifier_ready(); +} + +/* +============ +purifier_rapidfire - choose which rapid fire animation to use +============ +*/ +void purifier_rapidfire (void) +{ + + if (self.counter ==0) + purifier_rapidfire1L(); + else if (self.counter ==1) + purifier_rapidfire1R(); + else if (self.counter ==2) + purifier_rapidfire2L(); + else if (self.counter ==3) + purifier_rapidfire2R(); + + self.counter += 1; + self.attack_finished = time + .14; + + if (self.counter > 3) + self.counter =0; +} + +/* +============ +purifier_fire - shoot purifier. +============ +*/ +void() pal_purifier_fire = +{ + if ((self.artifact_active & ART_TOMEOFPOWER) && + (self.greenmana >= 8) && (self.bluemana >= 8)) + purifier_tomefire(); + else if ((self.greenmana >= 2) && (self.bluemana >= 2)) + purifier_rapidfire(); + + self.nextthink=time; +}; + + +/* +============ +purifier_ready - just sit there until fired +============ +*/ +void purifier_ready (void) +{ + self.weaponframe = $Rootpose; + self.wfs = $Rootpose; + self.th_weapon=purifier_ready; +} + +/* +============ +purifier_deselect - purifier was just unchosen. Remove from view +============ +*/ +void purifier_deselect (void) +{ + self.wfs = advanceweaponframe($Select12,$Select1); + self.th_weapon=purifier_deselect; + self.oldweapon = IT_WEAPON4; + + if (self.wfs == WF_LAST_FRAME) + W_SetCurrentAmmo(); +} + +/* +============ +purifier_select - purifier was just chosen. Bring into view +============ +*/ +void purifier_select (void) +{ + self.wfs = advanceweaponframe($select1,$select12); + self.weaponmodel = "models/purifier.mdl"; + self.th_weapon=purifier_select; + self.counter = 0; + + if (self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + purifier_ready(); + } +} + diff --git a/quake.hc b/quake.hc new file mode 100644 index 0000000..49cd381 --- /dev/null +++ b/quake.hc @@ -0,0 +1,127 @@ +/* +========================================= +QUAKE.HC +MG + +EarthQuakes! +========================================= +*/ + +void() ShakeRattleAndRoll = +{ +entity head; +float inertia; +float richter; +float dist; +float rand,boost; +vector dir; + + head = findradius(self.origin, self.mass); + richter=self.mass/100*(self.lifetime-time)/3; + +//FIXME: Add particle dust + while (head) + { + if ((head.movetype==MOVETYPE_STEP||head.movetype==MOVETYPE_WALK||head.movetype==MOVETYPE_PUSHPULL)&&head.solid!=SOLID_BSP&&head.mass<500 && head != self.owner && ((head.classname != "monster_golem_bronze") &&(head.classname != "monster_golem_iron") && (head.classname != "monster_golem_stone")&& (head.classname != "monster_golem_crystal"))) + { +// bprint(head.classname); + dist=vlen(self.origin-head.origin)/self.mass; + if(!head.mass) + inertia=1; + else + inertia=head.mass/10; + if((!head.flags2&FL_ALIVE)&&head.takedamage&&head.health&&random()<0.2&&head!=self.owner) + T_Damage(head,self,self.owner,richter*dist); + if(head.flags&FL_ONGROUND) + { + if(head!=self.owner) + { + if(head.classname=="player") + { + head.punchangle_x=random()*10 - 5; + head.punchangle_y=random()*8 - 4; + head.punchangle_z=random()*8 - 4; + } + else if(head.flags2&FL_ALIVE) + { + head.angles_y+=random()*20 - 10; + rand=random()*6 - 3;//FIXME: Remember old angles + if(head.angles_x+rand>30||head.angles_x+rand<-30) + head.angles_x-=rand; + else + head.angles_x+=rand; + rand=random()*6 - 3; + if(head.angles_z+rand>30||head.angles_z+rand<-30) + head.angles_z-=rand; + else + head.angles_z+=rand; + } + else + { + if(head.movetype!=MOVETYPE_BOUNCE) + { + head.oldmovetype=head.movetype; + head.movetype=MOVETYPE_BOUNCE; + } + else if(!head.oldmovetype) + head.oldmovetype=MOVETYPE_BOUNCE; + head.avelocity_z= random(1,10); + head.avelocity_y= random()*720 - 360; + head.avelocity_x= random()*720 - 360; + } + boost= (random(100)+25)/inertia*richter*dist; + if(boost>100) + boost=100; + head.velocity_z+=boost; + } + if(self.owner.classname=="monster_golem_bronze") + {//Make Bronze G make you drift towards him + dir=normalize(self.owner.origin-head.origin); + dir_z=0; + head.velocity=head.velocity+dir*((random()*50 - 25)/inertia*richter*dist); + } + else + { + head.velocity_y+= (random()*50 - 25)/inertia*richter*dist; + head.velocity_x+= (random()*50 - 25)/inertia*richter*dist; + head.flags(-)FL_ONGROUND; + } + } + if(self.lifetimetime) + self.think = ShakeRattleAndRoll; + else + self.think=SUB_Remove; + self.nextthink = time + 0.1; +}; + +void (float richter) MonsterQuake = +{ + newmis=spawn(); + newmis.owner=self; + newmis.solid=SOLID_NOT; + newmis.movetype=MOVETYPE_NONE; + newmis.classname="quake"; + newmis.think=ShakeRattleAndRoll; + newmis.nextthink=time; + newmis.mass=fabs(richter); + newmis.lifetime=time + 3; + setorigin(newmis,self.origin); +//FIXME: Replace explosion with some other quake-start sound + sound(newmis,CHAN_AUTO,"weapons/explode.wav",1,ATTN_NORM); + sound(newmis,CHAN_AUTO,"fx/quake.wav",1,ATTN_NORM); +}; + diff --git a/rat.hc b/rat.hc new file mode 100644 index 0000000..614a5e8 --- /dev/null +++ b/rat.hc @@ -0,0 +1,284 @@ +/* + * $Header: /HexenWorld/Siege/rat.hc 3 5/25/98 1:39p Mgummelt $ + */ + +// Scuttle +//$frame swalk1 swalk2 swalk3 swalk4 swalk5 +//$frame swalk6 swalk7 swalk8 swalk9 swalk10 +//$frame swalk11 swalk12 swalk13 swalk14 swalk15 +//$frame swalk16 + +void() rat_wait; +void() rat_noise; +void rat_die_wait() +{ + if(self.health<-80) + { + chunk_death(); + return; + } + if(!self.velocity) + { + if(random()<0.5) + self.angles_x=0; + else + self.angles_x=180; + self.avelocity='0 0 0'; + MakeSolidCorpse(); + return; + } + else + { + self.think=rat_die_wait; + thinktime self : 0.5; + } +} + +void rat_death (void) +{ + if(self.health<-80) + { + chunk_death(); + return; + } + +vector bounce_vel; + bounce_vel=normalize(self.origin-damage_attacker.origin); + bounce_vel*=random(self.health*-30); + self.velocity=bounce_vel; + self.velocity_z=random(150,450); + self.flags(-)FL_ONGROUND; + self.movetype=MOVETYPE_BOUNCE; + self.avelocity_x=random(self.health*10) - self.health; + self.avelocity_y=random(self.health*10) - self.health; + self.avelocity_z=random(self.health*10) - self.health; + self.think=rat_die_wait; + thinktime self : 0; +} + +void ratrun(void) +{ +entity player; +float player_see_me; + self.frame += 1; + + thinktime self : HX_FRAME_TIME; + self.think = ratrun; + + AdvanceFrame(0,17); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); +// dprint(ftos(self.ideal_yaw)); +// dprint("\n"); + ChangeYaw(); + + if(pointcontents(self.origin+'0 0 7')!=CONTENT_EMPTY) + { + if(pointcontents(self.origin)==CONTENT_LAVA) + { +// dprint("lava death\n"); + chunk_death(); + } + else + { + self.velocity_z=1; + self.flags(+)FL_SWIM; + } + } + else + self.velocity_z=-1; + + if((random()<0.1||self.origin==self.oldorigin)&&self.pain_finishedself.lifetime) + { + if(self.goalentity.classname=="tempgoal") + remove(self.goalentity); + remove(self); + } + if(self.frags>=10) + { + self.frags=0; + makevectors(self.angles); + newmis=spawn(); + setorigin(newmis,v_forward*-1000+v_right*(random()*100 - 50)); + remove(self.goalentity); + self.goalentity=newmis; + } + } + if(!walkmove(self.angles_y,random(3,7),FALSE)) + { +//TEMP + remove(self); +// self.frags+=1; + } +} + +void rat_wait () +{ + if(vlen(self.goalentity.origin-self.origin)>56) + self.think=ratrun; + else + self.think=rat_wait; + thinktime self : 0.05; +} + +void rat_noise (void) +{ + sound(self,CHAN_VOICE,"misc/squeak.wav",1,ATTN_NORM); +} + +void rat_touch (void) +{ + return; +} + +//========================================================================== +// +// monster_ratnest +// +//========================================================================== + +/*QUAKED monster_rat (1 0.3 0) (-3 -3 0) (3 3 7) +If the rat is targeted to a path, the rats will follow that path +------- key / value ---------------------------------- +------- spawnflags ----------------------------------- +AMBUSH +*/ +void rat_make_goal (void) +{ +vector goaldir; + goaldir=self.angles; + goaldir_y=self.ideal_yaw; + makevectors(goaldir); + newmis=spawn(); + newmis.effects=EF_NODRAW; + setmodel(newmis,"models/null.spr"); + setorigin(newmis,self.origin+v_forward*1000); + self.goalentity=newmis; + newmis.classname="tempgoal"; + thinktime newmis : 30; + newmis.think=SUB_Remove; +} + +void rat_stupor (void) +{ + self.angles_y+=random(-2,2); + self.frame=random(17); + self.think=rat_stupor; + thinktime self : random(0.3,1.3); +} + +void rat_go (void) +{ + self.th_stand = ratrun; + self.th_walk = ratrun; + self.think=ratrun; + thinktime self : 0; +} + +void monster_rat (void) +{ +//FIXME: DAMN RAT JUMPS UP IN AIR AND GET STUCK IN EACH OTHER!!!!!!!!!!! + if(!self.flags2&FL_SUMMONED) + { + precache_model("models/rat.mdl"); + precache_sound("misc/squeak.wav"); + self.th_stand = rat_stupor; + self.th_walk = rat_stupor; + self.use=rat_go; + } + else + { + self.th_stand = ratrun; + self.th_walk = ratrun; + } + + setmodel(self, "models/rat.mdl"); + + self.movetype = MOVETYPE_STEP; + self.solid = SOLID_SLIDEBOX; + if(pointcontents(self.origin)!=CONTENT_EMPTY) + { + self.flags(+)FL_SWIM; + self.angles_x=10; + } + + self.touch=rat_touch; + self.classname="monster_rat"; + + setsize(self, '-3 -3 0', '3 3 7'); + self.health = 3; + + self.thingtype=THINGTYPE_FLESH; + self.th_run = ratrun; + self.th_melee = ratrun; + self.th_missile = ratrun; + self.th_pain = rat_noise; + self.th_die = rat_death; + + self.flags(+)FL_MONSTER; + self.yaw_speed = 10; + self.lifetime = time+10; + + if(!self.target) + { + self.ideal_yaw=random(360); +// self.movetype=MOVETYPE_NOCLIP; +// self.solid=SOLID_NOT; + rat_make_goal(); + } + + walkmonster_start(); +} + +/*QUAKED monster_ratnest (1 0.3 0) (-20 -20 0) (20 20 10) +A group of 3 to 6 rats that flee when triggered +If the nest is targeted to a path, the rats will follow that path +------- key / value ---------------------------------- +------- spawnflags ----------------------------------- +AMBUSH +*/ +void monster_ratnest(void) +{ + precache_model("models/rat.mdl"); + precache_sound("misc/squeak.wav"); + self.use=barrel_die; +} + diff --git a/raven.hc b/raven.hc new file mode 100644 index 0000000..cb1c5c2 --- /dev/null +++ b/raven.hc @@ -0,0 +1,617 @@ +/* + * $Header: /HexenWorld/Siege/raven.hc 3 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\monsters\RAVEN\FINAL\raven.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\monsters\RAVEN\FINAL +$origin 0 0 0 +$base BASE skin +$skin skin +$flags 0 + +// +$frame 1stpec1 1stpec2 1stpec3 1stpec4 1stpec5 +$frame 1stpec6 1stpec7 1stpec8 1stpec9 1stpec10 +$frame 1stpec11 1stpec12 1stpec13 1stpec14 1stpec15 +$frame 1stpec16 1stpec17 1stpec18 1stpec19 1stpec20 +$frame 1stpec21 1stpec22 1stpec23 1stpec24 + +// +$frame 2ndpec1 2ndpec2 2ndpec3 2ndpec4 2ndpec5 +$frame 2ndpec6 2ndpec7 2ndpec8 2ndpec9 2ndpec10 +$frame 2ndpec11 2ndpec12 2ndpec13 + +// +$frame bounce1 bounce2 bounce3 bounce4 bounce5 +$frame bounce6 bounce7 bounce8 + +// +$frame death1 + +// +$frame down1 + +// +$frame fastfly1 fastfly2 fastfly3 fastfly4 fastfly5 + +// +$frame flaunt1 flaunt2 flaunt3 flaunt4 flaunt5 +$frame flaunt6 flaunt7 flaunt8 + +// +$frame fold1 fold2 fold3 fold4 fold5 +$frame fold6 fold7 fold8 fold9 fold10 +$frame fold11 fold12 fold13 fold14 fold15 + +// +$frame grabing1 grabing2 grabing3 grabing4 grabing5 + +// +$frame land1 land2 land3 land4 land5 + +// +$frame lowlft1 + +// +$frame lowrght1 + +// +$frame POLY + +// +$frame root1 + +// +$frame shit1 shit2 shit3 shit4 shit5 +$frame shit6 shit7 + +// +$frame slowfly1 slowfly2 slowfly3 slowfly4 slowfly5 +$frame slowfly6 slowfly7 slowfly8 slowfly9 + +// +$frame soarght1 soarlft1 soar1 + +// +$frame takeoff1 takeoff2 takeoff3 takeoff4 takeoff5 + +// +$frame upleft1 + +// +$frame uprght1 + +//NOTE: Need Raven chunks (feathers) +// needs "Nevermore" sound, squawk sound, feather flapping sound + +void()raven_flap_fast; +void()raven_glide; +void()raven_glide_right; +void()raven_glide_left; +void()raven_hop_wings_out; +void()raven_stand; +void()raven_slowdown; +void()raven_land; +void()raven_fold_wings; +void()raven_ruffle_end; +void()raven_peck_up1; +void()raven_peck_up_all; +void()raven_peck_up2; +void()raven_peck2; +void()raven_peck_down; +void()raven_peck_down1; +void()raven_peck_down2; + +void drop_feathers() +{ +vector ofs; + newmis=spawn(); + newmis.movetype=MOVETYPE_FLY; + newmis.avelocity_y=random(-200,200); + newmis.angles_x=random(-90,90); + newmis.velocity_z=random(-100); + ofs=RandomVector('32 32 32'); + newmis.think=SUB_Remove; + thinktime newmis : 3; + setmodel(newmis,"models/fether.mdl"); + setorigin(newmis,self.origin+ofs); +} + + +/* +--------------- +IN AIR +--------------- +*/ +void raven_takeoff (void) [++ $takeoff1 .. $takeoff5] +{ +//after unfold, jumps in air, goes to fast flap + ai_walk(3+self.frame-$takeoff1); + if(cycle_wrapped) + { + self.flags(+)FL_FLY; + self.movetype=MOVETYPE_FLY; + self.think=raven_flap_fast; + thinktime self : 0; + } +} + +void raven_flap_fast (void) [++ $fastfly1 .. $fastfly5] +{ +//Taking off or flying fast + ai_walk(self.speed+(self.frame-$fastfly1)*2); + if(cycle_wrapped&&random()<0.5) + { + self.think=raven_glide; + thinktime self : 0; + } +} + +void raven_flap_slow (void) [++ $slowfly1 .. $slowfly9] +{ +//used every now and then when gliding + ai_walk(self.speed+self.frame-$slowfly1); +} + +void raven_glide_think () +{ + ai_walk(self.speed); + if(self.goalentity.origin_zself.angles_y) + { + self.think=raven_glide_right; + thinktime self : 0; + } + else if(self.ideal_yaw>self.angles_y) + { + self.think=raven_glide_left; + thinktime self : 0; + } + else + { + self.think=raven_glide; + thinktime self : 0; + } +} + +void raven_glide (void) +{ + self.frame=$soar1; + if(self.angles_z>0) + self.angles_z-=1; + else if(self.angles_z<0) + self.angles_z+=1; + raven_glide_think(); +} + +void raven_glide_right (void) +{ +//Add some roll + self.frame=$soarght1; + if(self.angles_z>-15) + self.angles_z-=1; + raven_glide_think(); +} + +void raven_glide_left (void) +{ +//Add some roll + self.frame=$soarlft1; + if(self.angles_z<15) + self.angles_z+=1; + raven_glide_think(); +} + +void raven_slowdown (void) [++ $grabing1 .. $grabing5] +{ +//landing or pulling off a piece or slowing down to grab something + ai_walk(self.speed); + if(self.msg3=="landing") + if(self.speed>1) + self.speed-=0.1; + if(self.flags&FL_ONGROUND) + { + self.angles_z=0; + self.msg3=""; + self.think=raven_land; + thinktime self : 0; + } + if(self.angles_z>0) + self.angles_z-=1; + else if(self.angles_z<0) + self.angles_z+=1; +} + +void raven_land (void) [++ $land1 .. $land5] +{ +//hitting the ground, comes from slowdown to flaunt + ai_walk(1); + if(cycle_wrapped) + { + self.flags(-)FL_FLY; + self.movetype=MOVETYPE_STEP; + self.think=raven_hop_wings_out; + thinktime self : 0; + } +} + + + +/* +--------------- +ON GROUND +--------------- +*/ +void raven_hop_wings_out (void) [++ $flaunt1 .. $flaunt8] +{ +//flaunting, also after landing to folding + ai_walk(5); + if(cycle_wrapped) + { + if(self.msg3!="threatening"||random()<0.3) + { + self.think=raven_fold_wings; + thinktime self : 0; + } + } +} + +void raven_fold_wings (void) [++ $fold1 .. $fold15] +{ +//fold wings away after flaunting or landing + if(cycle_wrapped) + { + self.think=raven_stand; + thinktime self : 0; + } +} + +void raven_open_wings (void) [-- $fold15 .. $fold1] +{ +//open wings to flaunt or take off, or just randomly to ruffle + if(cycle_wrapped) + { + if(self.msg3=="taking off") + self.think=raven_flap_fast; + else if(self.msg3=="threatening") + self.think=raven_hop_wings_out; + thinktime self : 0; + } + else if(random()<0.3) + { + self.think=raven_fold_wings; + thinktime self : 0; + } +} + +void raven_hop (void) [++ $bounce1 .. $bounce8] +{ +//hopping around, no flying + ai_walk(2); + if(cycle_wrapped) + { + self.think=raven_stand; + thinktime self : 0; + } +} + +void raven_shit (void) [++ $shit1 .. $shit7] +{ +//hold and drop shit on $shit6 + if(self.frame==$shit6) + thinktime self : 0.77; + else if(cycle_wrapped) + { + self.think=raven_stand; + thinktime self : 0; + } +} + +void raven_ruffle_start (void) [++ $shit1 .. $shit3] +{ +//frames 1-3 ping-pong for feather ruffle + if(cycle_wrapped) + { + self.think=raven_ruffle_end; + thinktime self : 0; + } +} + +void raven_ruffle_end (void) [-- $shit3 .. $shit1] +{ +//frames 1-3 ping-pong for feather ruffle + if(cycle_wrapped) + { + self.think=raven_stand; + thinktime self : 0; + } +} + +void raven_choose_look (entity targ) +{ +vector vec; +//FIXME: If !targ choose random dir + vec=normalize((targ.absmin+targ.absmax)*0.5-self.origin+self.view_ofs); + makevectors(self.angles); +} + +void raven_stand_think () +{ +float r; + if(!self.goalentity) + self.goalentity=find(world,classname,"obj_corpse1"); + + if(random()<0.3) + { + r=rint(random(1,10)); + if(r==1) + self.think=raven_shit; + else if(r==2) + self.think=raven_ruffle_start; + else if(r==3) + { + self.msg3="threatening"; + self.think=raven_open_wings; + } + else if(r==4) + self.think=raven_ruffle_start; + else if(r==5) + { + self.msg3="taking off"; + self.think=raven_open_wings; + } + else if(r==6) + self.think=raven_peck_down; + else + self.think=raven_hop; + thinktime self : 0; + } + else if(self.msg3=="looking") + raven_choose_look(world); + else + thinktime self : 0.05; +} + +void raven_stand (void) +{ + self.frame=$root1; + self.think=raven_stand_think; + thinktime self : 0; +} + +void raven_die (void) +{ + drop_feathers(); + if(self.health<-20) + chunk_death(); + else + { + self.frame=$death1; + self.flags(-)FL_FLY; + if(self.movetype!=MOVETYPE_BOUNCE) + self.movetype=MOVETYPE_BOUNCE; + self.angles_z=0; + self.avelocity_y=random(200,400); + MakeSolidCorpse(); + } +} + + + +/* +--------------- +LOOKING +--------------- +*/ +void raven_look_left_low (void) +{ + self.frame=$lowlft1; + self.th_stand(); +} + +void raven_look_right_low (void) +{ + self.frame=$lowrght1; + self.th_stand(); +} + +void raven_look_left_high (void) +{ + self.frame=$upleft1; + self.th_stand(); +} + +void raven_look_right_high (void) +{ + self.frame=$uprght1; + self.th_stand(); +} + +void raven_look_down (void) +{ + self.frame=$down1; + self.th_stand(); +} + + +/* +--------------- +EATING +--------------- +*/ +void peck_effect () +{ + makevectors(self.angles); + traceline(self.origin,self.origin+v_forward*16,FALSE,self); + SpawnPuff(trace_endpos,'0 0 20' , random(3,10),trace_ent); +} + +void raven_peck1 (void) [++ $1stpec8 .. $1stpec20] +{ + if(random()<0.2) + peck_effect(); + if(cycle_wrapped) + { + if(random()<0.2) + { + self.think=raven_peck_up1; + thinktime self : 0; + } + else if(random()<0.5) + { + self.think=raven_peck_up_all; + thinktime self : 0; + } + } + else if(random()<0.2) + { + self.think=raven_peck2; + thinktime self : 0; + } +} + +void raven_peck2 (void) [++ $2ndpec1 .. $2ndpec10] +{ + if(random()<0.2) + peck_effect(); + if(cycle_wrapped) + { + if(random()<0.2) + { + self.think=raven_peck_up2; + thinktime self : 0; + } + else if(random()<0.5) + { + self.think=raven_peck_up_all; + thinktime self : 0; + } + } + else if(random()<0.2) + { + self.think=raven_peck1; + thinktime self : 0; + } +} + +void raven_peck_down (void) [++ $1stpec1 .. $1stpec7] +{ + if(cycle_wrapped) + { + self.think=raven_peck1; + thinktime self : 0; + } +} + +void raven_peck_up_all (void) [-- $1stpec7 .. $1stpec1] +{ + if(cycle_wrapped) + { + if(random()<0.7) + self.think=raven_stand; + else + self.think=raven_peck_down; + thinktime self : 0; + } +} + +void raven_peck_up1 (void) [++ $1stpec21 .. $1stpec24] +{ + if(self.frame==$1stpec24) + { + self.think=raven_peck_down1; + thinktime self : random(0.3,1.3); + } +} + +void raven_peck_up2 (void) [++ $2ndpec11 .. $2ndpec13] +{ + if(self.frame==$2ndpec13) + { + self.think=raven_peck_down2; + thinktime self : random(0.3,1.3); + } +} + +void raven_peck_down1 (void) [-- $1stpec24 .. $1stpec21] +{ + if(cycle_wrapped) + { + if(random()<0.5) + self.think=raven_peck1; + else + self.think=raven_peck2; + thinktime self : 0; + } +} + +void raven_peck_down2 (void) [-- $2ndpec13 .. $2ndpec11] +{ + if(cycle_wrapped) + { + if(random()<0.5) + self.think=raven_peck1; + else + self.think=raven_peck2; + thinktime self : 0; + } +} + +/*QUAKED monster_raven (1 0 0) (-16 -16 0) (16 16 56) +Scavenger black bird of ill portent. +"Nevermore!" +*/ +void() monster_raven = +{ + if (!self.flags2&FL_SUMMONED) + { + precache_model2 ("models/raven.mdl"); + precache_model2 ("models/fether.mdl"); + precache_sound2 ("raven/squawk.wav"); +// precache_sound2 ("raven/nevermor.wav"); + } + self.solid = SOLID_SLIDEBOX; + self.takedamage=DAMAGE_YES; + self.thingtype=THINGTYPE_FLESH; + self.movetype = MOVETYPE_STEP; + self.view_ofs = '0 0 17'; + self.speed=10; + self.yaw_speed = 10; + self.health = 10; + self.mass = 1; + self.mintel=5; + + self.th_stand=raven_stand; + self.th_walk=raven_hop; + self.th_run=raven_glide; +// self.th_pain=raven_pain; + self.th_melee=raven_peck_down; + self.th_missile=raven_shit; + self.th_jump=raven_takeoff; + self.th_die=raven_die; + + setmodel (self, "models/raven.mdl"); + + setsize (self, '-7 -7 0', '7 7 20'); + + walkmonster_start(); +}; diff --git a/ravenai.hc b/ravenai.hc new file mode 100644 index 0000000..4959fa3 --- /dev/null +++ b/ravenai.hc @@ -0,0 +1,298 @@ +/* + * $Header: /HexenWorld/Siege/ravenai.hc 3 5/25/98 1:39p Mgummelt $ + */ + +float() LocateTarget = +{ + return FindTarget(TRUE); +}; + +float MA_SUCCESSFUL = 0; +float MA_BLOCKED = -1; +float MA_CROSSED = -2; +float MA_NOWEAPON = -3; +float MA_TOOSOON = -4; +float MA_TOOFAR = -5; +float MA_NOATTACK = -6; + +float MA_MELEE = 1; +float MA_MISSILE = 2; +float MA_BOTH = 3; +float MA_FAR_MELEE = 4; +float MA_SHORT_MISSILE = 8; + +// You must perform the following call sometime before calling this function: +// enemy_range = range (self.enemy); +float(float AttackType, float ChanceModifier) CheckMonsterAttack = +{ + local vector spot1, spot2; + local entity targ; + local float chance; + + targ = self.enemy; + + if (self.classname == "monster_hydra") + if (self.enemy.watertype != CONTENT_WATER) + { + if (self.search_time < time) + { + self.monster_stage = 0; + self.enemy = world; + return 0; + } + return 0; + } + else self.search_time = time + 5; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if(trace_ent.thingtype>=THINGTYPE_WEBS) + traceline (trace_endpos, spot2, FALSE, trace_ent); + + if (trace_ent != targ) + if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep")) + return MA_BLOCKED; // don't have a clear shot + + if (trace_inopen && trace_inwater) + return MA_CROSSED; // sight line crossed contents + + if (enemy_range == RANGE_MELEE) + { // melee attack + if (AttackType & MA_SHORT_MISSILE) + { + if (random() < 0.5) + { + self.th_missile (); + return MA_SUCCESSFUL; + } + } + if (self.th_melee) + { + if (AttackType & MA_MELEE) + { + self.th_melee (); + return MA_SUCCESSFUL; + } + else + return MA_NOWEAPON; + } + } + +// missile attack + if (!self.th_missile || !(AttackType & (MA_MISSILE | MA_FAR_MELEE))) + { + return MA_NOWEAPON; + } + + if (time < self.attack_finished) + return MA_TOOSOON; + + if (enemy_range == RANGE_FAR) + return MA_TOOFAR; + + if (enemy_range == RANGE_MELEE) + { + chance = 0.9; + self.attack_finished = 0; + } + else if (enemy_range == RANGE_NEAR) + { + if (self.th_melee) + chance = 0.2; + else + chance = 0.4; + } + else if (enemy_range == RANGE_MID) + { + if (self.th_melee) + chance = 0.05; + else + chance = 0.1; + } + else + chance = 0; + + chance = chance * ChanceModifier; + if (chance > 0.95) chance = 0.95; + + if (random () < chance) + { + if (self.th_melee) + { // quake c wouldn't allow me to put this in on if!!! + if (AttackType & MA_FAR_MELEE) + { + self.th_melee (); + } + else + { + self.th_missile (); + } + } + else + { + self.th_missile (); + } +// SUB_AttackFinished (random(2,0)); + SUB_AttackFinished (random(8,0)); + return MA_SUCCESSFUL; + } + + return MA_NOATTACK; +}; + +float (vector offset, vector to_where)monster_checkpos = +{ + // This function will trace 2 lines - the first line will go from the origin to the offset from the origin. + // If this could be done atleast half way, then a 2nd trace is done from the end point of the first trace + // to the final destination. If this was mostly successful, then the function will return true, otherwise + // false. You would use this function in a situation where you want to see if the enemy is visibile from + // your right side, so you first see if you can go do the right side, then go forward from there to the enemy. + local vector start; + local float length; + + start = self.origin + offset; + traceline (self.origin, start, FALSE, self); + if (trace_fraction < 0.5) + { // Couldn't get to the offset + return FALSE; + } + length = vlen(self.origin-start) * trace_fraction; + start = trace_endpos; + traceline (start,to_where, FALSE, self); + if (trace_ent == self.enemy || trace_fraction > 0.98) + { // We found the enemy! + length = length + vlen(start-self.enemy.origin) * trace_fraction; + return length; + } + + return FALSE; +}; + + +void (float l, float r, float u, float d, float last_move, vector where) find_path = +{ + // This function will check to see if an enemy can be located from the top, bottom, left, and right sides. + // The l, r, u, d parameters specify the order for which the search should be done. If it couldn't find + // the enemy, then it will try the last seen position of the enemy. last_move indicates that the previous + // move was successful (i.e. the monster could move forward). where is the position to check for. + local float length; + local float newyaw; + local float newz; + local float c; + local float retval; +// local vector a, b; + + makevectors (self.angles); + length = 99999; + newyaw = self.ideal_yaw; + newz = self.velocity_z; + + c = 0; + while(c<=4) + { // We have 5 checks to do + if (c == 0 && last_move) + { // Try checking forward + retval = monster_checkpos(v_forward*300,where); + if (retval && retval < length) + { + //dprint("found you to the forward\n"); + self.monster_duration = 18 + 5; + length = retval; + } + } + if (c == l) + { // Try checking to the left + retval = monster_checkpos(v_right*-200,where); + if (retval && retval < length) + { + //dprint("found you to the left\n"); + newyaw = self.angles_y + 90; + self.monster_duration = 18 + 5; + length = retval; + } + } + else if (c == r) + { // Try checking to the right + retval = monster_checkpos(v_right*200,where); + if (retval && retval < length) + { + //dprint("found you to the right\n"); + newyaw = self.angles_y - 90; + self.monster_duration = 18 + 5; + length = retval; + } + } + else if (c == u) + { // Try checking to the top + retval = monster_checkpos(v_up*200,where); + if (retval && retval < length) + { + //dprint("found you to the up\n"); + newz = 30; + self.monster_duration = 18 + 5; + length = retval; + } + } + else if (c == d) + { // Try checking to the bottom + retval = monster_checkpos(v_up*-200,where); + if (retval && retval < length) + { + //dprint("found you to the down\n"); + newz = -30; + self.monster_duration = 18 + 5; + length = retval; + } + } + c = c + 1; + } + + if (length == 99999 && self.monster_last_seen != where) + { // If we didn't find a direction, and we haven't done this, try looking where the enemy + // was last seen + find_path(l,r,u,d,0,self.monster_last_seen); + //dprint("Using last seen\n"); + } + else + { + self.ideal_yaw = newyaw; + self.velocity_z = newz; + } +}; + +float () FindDir = +{ // Monster couldn't go in the direction it is pointed to, so find one it can go to + local vector a,b,c; + local float inc,step; + + if (random() < 0.5) inc = 45; + else inc = -45; + + c = '0 0 0'; + c_y = c_y + inc; + + step = 0; + while(step < 6) + { // 7 directions to check (45 degrees each) + makevectors (self.angles + c); + a = self.origin + self.view_ofs; + b = a + v_forward*100; + + traceline (a, b, FALSE, self); + + if (trace_fraction > 0.9) + { // We can mostly go this direction + return self.angles_y + c_y; + //dprint(" found\n"); + } + c_y = c_y + inc; + step = step + 1; + } + + return self.angles_y; +}; + diff --git a/ravenstf.hc b/ravenstf.hc new file mode 100644 index 0000000..19918b4 --- /dev/null +++ b/ravenstf.hc @@ -0,0 +1,763 @@ +/* + * $Header: /HexenWorld/Siege/ravenstf.hc 31 5/25/98 1:39p Mgummelt $ + */ + +// For building the model +$cd Q:\art\models\weapons\newass +$origin 0 0 0 +$base BASE SKIN +$skin SKIN +$flags 0 + +// +$frame rootpose + +// +$frame fire1 fire2 fire3 fire4 + +// +$frame select1 select2 select3 select4 select5 +$frame select6 select7 select8 select9 select10 +$frame select11 select12 + +float ravenshot_speed = 1200; + +void ravenstaff_fire (void); +void ravenstaff_idle (void); +void split (void); +void raven_track(void); +void raven_flap(void); +void raven_touch (void); +void raven_track_init(void); +void ravenmissile_explode(void); + +void raven_spark (void) +{ + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_HWRAVENDIE); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z - 10); + multicast(self.origin,MULTICAST_PHS_R); + + +/* CreateWhiteSmoke(self.origin + '0 0 -10', '0 8 -10', HX_FRAME_TIME *3); + CreateRedSmoke(self.origin + '0 0 -10', '0 0 -10', HX_FRAME_TIME *3); + CreateWhiteSmoke(self.origin + '0 0 -10', '0 -8 -10', HX_FRAME_TIME *3); + sound(self,CHAN_WEAPON,"raven/death.wav",1,ATTN_NORM); +*/ + remove(self); +// self.touch = SUB_Null; +// self.effects=EF_NODRAW; +// self.think=SUB_Remove; +// thinktime self : HX_FRAME_TIME; +// thinktime self : HX_FRAME_TIME * 2; + +} + +void raven_death_init (void) +{ + self.raven_owner.raven_cnt -= 1; +// dprint("Dec class: "); +// dprint(self.raven_owner.classname); +// dprint("\n"); + + self.takedamage = DAMAGE_NO; + + traceline(self.origin,self.origin + '0 0 600',FALSE,self); + if (trace_fraction < 1) + { + self.touch = raven_spark; + self.nextthink = 0; + } + else + { + self.touch = raven_spark; + self.think = raven_spark; + thinktime self : 1; + } + + self.velocity = normalize('0 0 600'); + self.velocity = self.velocity * 400; + + self.angles = vectoangles(self.velocity); +} + +void raven_bounce(void) +{ + self.flags (-) FL_ONGROUND; + + self.angles = vectoangles(self.velocity); // Flip it around to match the velocity set by the BOUNCEMISSLE code + self.angles_y += random(-90,90); // Change it's yaw a little + self.angles_x = random(-20,20); // Change it's pitch a little + + makevectors (self.angles); + self.velocity = normalize (v_forward); + self.velocity = self.velocity * 600; + + self.think = raven_flap; + self.nextthink = time + HX_FRAME_TIME; + + self.think1 = raven_track_init; + self.next_action = time + HX_FRAME_TIME * random(2,4); + + self.touch = raven_touch; +} + +// Bite the enemy +void raven_touch (void) +{ + if ((other == self.enemy) && (other.takedamage != DAMAGE_NO)) + { + if (other.monsterclass >= CLASS_BOSS) // Bosses only take half damage + T_Damage(other,self,self.owner,20); + else + T_Damage(other,self,self.owner,40); + + if(other.flags & FL_CLIENT) + { + if(random() < .5) + {//lights out! + stuffcmd(other, "df\n"); + } + } + self.damage_max += 40; + SpawnPuff (self.origin, '0 0 -5', random(5,10),other); + MeatChunks (self.origin,self.velocity*0.5+'0 0 20', 2,other); +// weapon_sound(self, "weapons/gauntht1.wav"); //sigh, no weapon_sound for packed items + sound(self,CHAN_WEAPON,"weapons/gauntht1.wav",1,ATTN_NORM); + } + + if (self.damage_max > 250) + raven_death_init(); + else + { + self.touch = SUB_Null; + self.think = raven_bounce; + self.nextthink = time + .05; // Need to wait a little before flipping model to match velocity + } + + if ((self.lifetime < time) || (self.raven_owner.raven_cnt > 6)) + { + raven_death_init(); + return; + } +} + +// Search for an enemy +void raven_search(void) +{ + entity victim; + + self.nextthink = time + HX_FRAME_TIME; // Gotta flap + self.think = raven_flap; + + victim = findradius( self.origin,1000); + while(victim) + { // the controller check is for the summoned imp + if (((victim.flags & FL_MONSTER) || (victim.flags & FL_CLIENT)) && + (victim.owner != self) && (victim.controller != self.owner) && (victim.health>0) && (victim!=self.owner)) + { + if (coop && self.enemy.team == self.team) + victim = victim; // Do nothing if its a player on your team. + else + { + traceline(self.origin,victim.origin,TRUE,self); + if (trace_fraction == 1.0) + { + self.enemy = victim; + self.think1 = raven_track; + self.think1 = raven_track_init; + self.next_action = time + .1; + self.searchtime = 0; + return; + } + } + } + victim = victim.chain; + } + + self.think1 = raven_search; + self.next_action = time + HX_FRAME_TIME * 3; + + if (self.searchtime == 0) // Done only on birth of raven + { + self.searchtime = time + .5; + + self.angles_y = random(0, 360); + self.angles_x = 0; + + makevectors (self.angles); + self.velocity = normalize (v_forward); + self.velocity = self.velocity * 600; + self.last_vel = self.velocity; + + } + + if ((self.searchtime < time) || (self.lifetime < time) || (self.raven_owner.raven_cnt > 6)) + raven_death_init(); +} + + + +// +// Chase after the enemy +// +void raven_track (void) +{ + vector delta; + vector hold_spot; + +// dprint("\n trk:"); +// dprint(self.enemy.classname); + + // The FL_MONSTER flag gets flipped when it becomes a head + if ((self.enemy.health <= 0) || (self.enemy == world) || (!self.enemy.flags & FL_MONSTER)) + raven_search(); + else + { + traceline(self.origin,self.enemy.origin,TRUE,self); + if (trace_fraction == 1) + { + hold_spot = self.enemy.origin; + hold_spot_z += self.enemy.maxs_z; // Hit 'em on the head + delta = hold_spot - self.origin; + + self.velocity = normalize(delta); + self.velocity = self.velocity * 600; + self.angles = vectoangles(self.velocity); +// raven_check_vel(); + self.think1 = raven_track; + self.next_action = time + HX_FRAME_TIME * 3; + + self.think = raven_flap; + self.nextthink = time + HX_FRAME_TIME; + } + else + raven_search(); + } + + if ((self.lifetime < time) || (self.raven_owner.raven_cnt > 6)) + { + raven_death_init(); + return; + } +} + +void raven_track_init (void) +{ + vector delta; + vector hold_spot; + + if ((self.enemy.health <= 0) || (self.enemy == world)) + raven_search(); + else + { + hold_spot = self.enemy.origin; + hold_spot_z += self.enemy.maxs_z; + delta = hold_spot - self.origin; + self.velocity = normalize(delta); + self.angles = vectoangles(self.velocity); + self.idealpitch = self.angles_x; + + makevectors(self.angles); + self.velocity = normalize(v_forward); + self.velocity = self.velocity * 600; + self.pitchdowntime = time + HX_FRAME_TIME *3; + + self.think = raven_track; + self.nextthink = time; + } +} + +// Everything comes back to here +void raven_flap(void) +{ +// raven_check_vel(); + AdvanceFrame(0,7); + + if ((self.frame == 1) && (random() < .2)) + { +// weapon_sound(self, "raven/squawk2.wav"); //doesn't work with packing! + sound(self,CHAN_VOICE,"raven/squawk2.wav",1,ATTN_NORM); + } + if (self.next_action < time) + { + self.think = self.think1; + self.nextthink = time; + } + else + { +// ChangeYaw(); + self.think = raven_flap; + self.nextthink = time + HX_FRAME_TIME; + } + + if ((self.lifetime < time) || (self.raven_owner.raven_cnt > 6)) + { + raven_death_init(); + return; + } +} + + +/*-------------------- +Create one raven +----------------------*/ +void create_raven(void) +{ + entity missile; + vector spot1, spot2; + + missile = spawn (); + missile.frags=TRUE; + missile.owner = self.owner; + missile.raven_owner = self.raven_owner; //used to decrement count correctly + + missile.movetype = MOVETYPE_BOUNCEMISSILE; + missile.solid = SOLID_BBOX; + missile.takedamage = DAMAGE_NO; + + // set missile speed + makevectors (self.v_angle); + missile.velocity = normalize (v_forward); + missile.velocity = missile.velocity * 600; + missile.angles = vectoangles(missile.velocity); + missile.searchtime = 0; + missile.yaw_speed = 50; + + setmodel (missile, "models/ravproj.mdl"); + setsize (missile, '-8 -8 8', '8 8 8'); + + // had to remove the offset on origin + setorigin (missile, self.origin + self.proj_ofs - v_forward * 14); + + missile.touch = raven_touch; + missile.lifetime = time + 4 + random(); + missile.classname = "bird_missile"; +// sound(missile,CHAN_VOICE,"raven/ravengo.wav",1,ATTN_NORM); + + // Find an enemy + makevectors(self.v_angle); + spot1 = self.origin + self.proj_ofs; + spot2 = spot1 + (v_forward*600); // Look ahead + traceline(spot1,spot2,FALSE,self); + missile.th_die=raven_death_init; + + // We have a victim in sights + if ((trace_ent!=world) && + (trace_ent.flags & FL_MONSTER) && (trace_ent.owner != self) && (trace_ent.health>0)) + { + missile.enemy = trace_ent; + + missile.nextthink = time + HX_FRAME_TIME; + missile.think = raven_flap; + + missile.next_action = time + .01; + missile.think1 = raven_track; + missile.think1 = raven_track_init; + } + else + { + missile.nextthink = time + .01; + missile.think = raven_search; + } +} + +void ravenmissile_explode (void) +{ +local vector vel; + + makevectors (self.v_angle); + vel = normalize (v_forward); + vel = vel * 600; + + create_raven(); + create_raven(); + create_raven(); + + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_HWRAVENEXPLODE); + WriteCoord (MSG_MULTICAST, self.origin_x); + WriteCoord (MSG_MULTICAST, self.origin_y); + WriteCoord (MSG_MULTICAST, self.origin_z); + multicast(self.origin,MULTICAST_PHS_R); +// sound(self,CHAN_VOICE,"raven/ravengo.wav",1,ATTN_NORM); + +/* + CreateWhiteSmoke(self.origin + '0 0 0','0 0 8',HX_FRAME_TIME * 3); + CreateWhiteSmoke(self.origin + '0 0 5','0 0 8',HX_FRAME_TIME * 3); + CreateWhiteSmoke(self.origin + '0 0 10','0 0 8',HX_FRAME_TIME * 3); +*/ + remove(self); + +} + +void ravenmissile_touch (void) +{ + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + if (other.health) + { +// sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + starteffect(CE_SM_EXPLOSION2 , self.origin); + self.enemy = other; + T_Damage(other,self,self,10); + } + ravenmissile_explode(); +} + +void ravenmissile_puff (void) +{ + makevectors(self.angles); + + if (self.lifetime < time) + ravenmissile_explode(); + else + { + thinktime self : HX_FRAME_TIME * 3; + self.think = ravenmissile_puff; + } +} + + +/*-------------------- +Launch all ravens +----------------------*/ +void launch_superraven (void) +{ + entity newmis; + + self.attack_finished = time + 1.0; + self.raven_cnt += 3; //considered from time of missile creation + + makevectors(self.v_angle); + + newmis = spawn(); + setmodel (newmis, "models/birdmsl2.mdl"); + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_BBOX; + newmis.takedamage = DAMAGE_NO; + newmis.owner = self; + newmis.raven_owner = self; + setsize (newmis, '0 0 0', '0 0 0'); + + newmis.velocity = normalize (v_forward); + newmis.velocity = newmis.velocity * 600; + newmis.angles = vectoangles(newmis.velocity); + setorigin(newmis, self.origin + self.proj_ofs + v_forward*10); + + newmis.touch = ravenmissile_touch; + newmis.lifetime = time + .5; + newmis.avelocity_z = 1000; + newmis.scale = .40; + thinktime newmis : HX_FRAME_TIME * 3; + newmis.think = ravenmissile_puff; + + self.punchangle_x= random(-3); + //TODO: kick +} + + +void ravenshot_touch (void) +{ + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + T_Damage (other, self, self.owner, self.dmg ); + +// sound (self, CHAN_WEAPON, "weapons/explode.wav", 1, ATTN_NORM); + + starteffect(CE_SM_EXPLOSION2 , self.origin); + + remove(self); + +} + +void create_raven_shot2(vector location,float add_yaw,float nexttime,float rotate,void() nextfunc) +{ + entity missile; + vector holdangle; + + missile = spawn (); + missile.owner = self.owner; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.solid = DAMAGE_YES; + missile.dmg = 50; + +// set missile speed + missile.angles = self.angles; + + holdangle = self.angles; +// holdangle_z = 0; + holdangle_x = 0 - holdangle_x; + holdangle_y += add_yaw; + makevectors (holdangle); + missile.velocity = normalize (v_forward); + missile.velocity = missile.velocity * ravenshot_speed; + + if (rotate) + missile.avelocity_z = 1000; + else + missile.avelocity_z = -1000; + + missile.touch = ravenshot_touch; + + setmodel (missile, "models/vindsht1.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, location); + + missile.classname = "set_missile"; + thinktime missile : nexttime; + missile.think = nextfunc; + +} + +void create_raven_shot1(vector location,float nexttime,void() nextfunc,vector fire_angle) +{ + entity missile; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + +// set missile speed + makevectors (fire_angle); + missile.velocity = normalize (v_forward); + missile.velocity = missile.velocity * ravenshot_speed; + + missile.avelocity_z = 1000; + + missile.angles = vectoangles(missile.velocity); + missile.dmg = 90; + + missile.touch = ravenshot_touch; + + setmodel (missile, "models/vindsht1.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, location); + + missile.classname = "set_missile"; + + thinktime missile : nexttime; + + missile.think = nextfunc; +} + +void missle_straight(void) +{ + vector holdangles; + + holdangles = self.angles; +// holdangles_z = 0; + holdangles_x = 0 - holdangles_x; + makevectors (holdangles); + + self.velocity = normalize (v_forward); + self.velocity = self.velocity * ravenshot_speed; + + return; +} + +void missle_straight1(void) +{ + vector holdangles; + + holdangles = self.angles; +// holdangles_z = 0; + holdangles_x = 0 - holdangles_x; + makevectors (holdangles); + + self.velocity = normalize (v_forward); + self.velocity = self.velocity * ravenshot_speed; + + create_raven_shot2(self.origin,-6,.2,1,missle_straight); + self.dmg = 50; + + starteffect(CE_HWSPLITFLASH, self.origin); + self.think = missle_straight; + thinktime self : .05; + +} + +void missle_straight2(void) +{ + vector holdangles; + + holdangles = self.angles; +// holdangles_z = 0; + holdangles_x = 0 - holdangles_x; + makevectors (holdangles); + + self.velocity = normalize (v_forward); + self.velocity = self.velocity * ravenshot_speed; + + create_raven_shot2(self.origin,6,.2,1,missle_straight); + self.dmg = 50; + + starteffect(CE_HWSPLITFLASH, self.origin); + self.think = missle_straight; + thinktime self : .05; + +} + + +void split (void) +{ + vector holdangles; + + // RIGHT SIDE + create_raven_shot2(self.origin,-5,.30,0,missle_straight1); + + // LEFT SIDE + create_raven_shot2(self.origin,5,.30,0,missle_straight2); + + starteffect(CE_HWSPLITFLASH, self.origin); + + self.dmg = 50; + holdangles = self.angles; +// holdangles_z = 0; + holdangles_x = 0 - holdangles_x; + makevectors (holdangles); + + self.velocity = normalize (v_forward); + self.velocity = self.velocity * ravenshot_speed; +} + +void launch_set (vector dir_mod) +{ + + self.attack_finished = time + 1.0; + + create_raven_shot1(self.origin + self.proj_ofs + v_forward*14,0.05,split,self.v_angle); +} + + +void ravenstaff_power (void) +{ + self.wfs=advanceweaponframe($fire1,$fire4); + self.th_weapon=ravenstaff_power; + + if (self.weaponframe==$fire1) + { + self.punchangle_x = -4; + launch_superraven(); + self.greenmana -= 16; + self.bluemana -= 16; + } + else if(self.weaponframe == $fire4) + { + self.weaponframe = $fire4; + self.th_weapon=ravenstaff_idle; + } + + thinktime self : HX_FRAME_TIME; +} + +void ravenstaff_normal (void) +{ + self.wfs=advanceweaponframe($fire1,$fire4); + self.th_weapon=ravenstaff_normal; + + if(self.weaponframe==$fire3) + { + self.punchangle_x = -4; + launch_set('0 0 0'); + self.greenmana -= 8; + self.bluemana -= 8; + } + + else if(self.wfs==WF_CYCLE_WRAPPED) + { + self.weaponframe = $rootpose; + self.th_weapon=ravenstaff_idle; + } + thinktime self : HX_FRAME_TIME; + +} + + +void ravenstaff_fire (void) +{ + vector holdvelocity; + + if ((self.artifact_active & ART_TOMEOFPOWER) && + (self.greenmana >= 16) && (self.bluemana >= 16)) + { +// dprintf("Raven count %s\n", self.raven_cnt); + if(self.raven_cnt<3) //this way it won't waste so much mana + { + weapon_sound(self, "raven/rfire2.wav"); +// sound (self, CHAN_WEAPON, "raven/rfire2.wav", 1, ATTN_NORM); + stuffcmd (self, "bf\n"); + ravenstaff_power(); + } + else + { + self.attack_finished = time + 0.5; + } + } + else if ((self.greenmana >= 8) && (self.bluemana >= 8)) + { + stuffcmd (self, "bf\n"); + makevectors(self.v_angle); + holdvelocity = normalize(v_right); + holdvelocity = holdvelocity * 10; + starteffect(CE_TELESMK1, self.origin + self.proj_ofs + v_forward * 14,holdvelocity,HX_FRAME_TIME * 3); +// starteffect(CE_TELESMK1, self.origin + self.proj_ofs + v_forward * 14,holdvelocity * -1,HX_FRAME_TIME * 3); +// sound (self, CHAN_WEAPON, "raven/rfire1.wav", 1, ATTN_NORM); + ravenstaff_normal(); + } + +} + +/* +============ +ravenstaff_ready - just sit there until fired +============ +*/ +void ravenstaff_idle (void) +{ + self.weaponframe= $rootpose; + self.th_weapon=ravenstaff_idle; +} + +void ravenstaff_select (void) +{ + self.wfs=advanceweaponframe($select1,$select12); + self.weaponmodel=("models/ravenstf.mdl"); + self.th_weapon=ravenstaff_select; + if(self.weaponframe==$select12) + { + self.attack_finished = time - 1; + ravenstaff_idle(); + } +} + +void ravenstaff_deselect (void) +{ + self.wfs=advanceweaponframe($select12,$select1); + self.th_weapon=ravenstaff_deselect; + thinktime self : HX_FRAME_TIME; + + self.oldweapon = IT_WEAPON4; + if(self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); + +} + diff --git a/reflect.hc b/reflect.hc new file mode 100644 index 0000000..4dcf1f3 --- /dev/null +++ b/reflect.hc @@ -0,0 +1,198 @@ +float REFLECT_RETURN = 1; +float REFLECT_TOGGLE = 2; +float REFLECT_START_OPEN = 4; + +void() reflect_trigger_touch; +void() reflect_go_down; + +entity reflect_spawn_field(vector fmins, vector fmaxs, entity door) +{ + local entity trigger; + local vector t1, t2; + + trigger = spawn(); + trigger.movetype = MOVETYPE_NOCLIP; + trigger.solid = SOLID_TRIGGER; + trigger.owner = self; + trigger.touch = reflect_trigger_touch; + + t1 = fmins; + t2 = fmaxs; + setsize (trigger, t1 - '30 30 30', t2 + '30 30 30'); + + return (trigger); +} + +void() reflect_crush = +{ + T_Damage(other,self, self,20); +}; + +void() reflect_touch = +{ +//vector newv; +vector org, vec, dir, endplane;//, dif, endspot; +float magnitude;//remainder, reflect_count, + + if ((other.movetype != MOVETYPE_FLYMISSILE) && (other.movetype != MOVETYPE_BOUNCEMISSILE)) return; + + if (other.safe_time>time && !self.inactive) return; + + dir = normalize(other.velocity); + magnitude=vlen(other.velocity); + org = other.origin; + vec = org + dir*31; + traceline (org, vec, TRUE, other); + + if(trace_fraction==1) + return; + + endplane=trace_plane_normal; + + dir+= 2*endplane; + dir=normalize(dir); + + other.safe_time = time + 100/magnitude; + other.velocity = dir*magnitude; + other.angles = vectoangles(other.velocity); + UpdateMissileVelocity(other); +}; + +void() reflect_trigger_touch = +{ + if (!self.inactive) + reflect_touch(); +}; + +void() reflect_hit_top = +{ + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.state = STATE_TOP; + self.think = reflect_go_down; + if (self.spawnflags & REFLECT_RETURN) + self.nextthink = self.ltime + self.wait; + else self.nextthink = -1; +}; + +void() reflect_hit_bottom = +{ + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.state = STATE_BOTTOM; +}; + +void() reflect_go_down = +{ + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + self.state = STATE_DOWN; + SUB_CalcMove (self.pos2, self.speed, reflect_hit_bottom); +}; + +void() reflect_go_up = +{ + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + self.state = STATE_UP; + SUB_CalcMove (self.pos1, self.speed, reflect_hit_top); +}; + +void() reflect_use = +{ + if (self.state == STATE_BOTTOM) + reflect_go_up(); + else if (self.state == STATE_TOP) + reflect_go_down(); +}; + +/*QUAK-ED func_reflect (0 .5 .8) ? RETURN TOGGLE STARTOPEN +Reflects any missile or flying object (moves as a door) +*/ +/* +void() func_reflect = +{ +//entity t; + + if (!self.t_length) + self.t_length = 80; + if (!self.t_width) + self.t_width = 10; + + if (self.soundtype == 0) + self.soundtype = 2; +// FIX THIS TO LOAD A GENERIC PLAT SOUND + + + if (self.soundtype == 1) + { + precache_sound2 ("plats/plat1.wav"); + precache_sound2 ("plats/plat2.wav"); + self.noise = "plats/plat1.wav"; + self.noise1 = "plats/plat2.wav"; + } + + if (self.soundtype == 2) + { + precache_sound2 ("plats/medplat1.wav"); + precache_sound2 ("plats/medplat2.wav"); + self.noise = "plats/medplat1.wav"; + self.noise1 = "plats/medplat2.wav"; + } + + SetMovedir (); + + self.classname = "reflect"; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + + self.blocked = reflect_crush; + + if (!self.speed) + self.speed = 150; + if (!self.wait) + self.wait = 3; + if (!self.lip) + self.lip = 4; + + self.pos1 = self.origin; + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + + self.state = STATE_BOTTOM; + + if (self.spawnflags & REFLECT_START_OPEN) + { + setorigin (self, self.pos2); + self.pos2 = self.pos1; + self.pos1 = self.origin; + } + + setorigin (self, self.pos2); + + self.movechain = reflect_spawn_field(self.absmin, self.absmax, self); + self.use = reflect_use; + self.touch = reflect_touch; + self.inactive = FALSE; +}; +*/ +/* +void() reflect_trigger_use = +{ +}; +*/ +/*QUAK-ED trigger_reflect (0 .5 .8) ? ACTIVATE +Reflects any missile or flying object +*/ +/* +void() trigger_reflect = +{ + self.use = reflect_trigger_use; + self.touch = reflect_trigger_touch; + + if (self.spawnflags & 1) + self.inactive = TRUE; + else + self.inactive = FALSE; + + InitTrigger (); +};*/ + diff --git a/rider.hc b/rider.hc new file mode 100644 index 0000000..8715097 --- /dev/null +++ b/rider.hc @@ -0,0 +1,707 @@ +/*QUAKED rider_path (0.5 0.3 0) (-8 -8 -8) (8 8 8) +Specifies a path point for a rider. You can specify +up to 4 other places that the rider can go after this +point. +-------------------------FIELDS------------------------- +path_id: number (id) of this path point +next_path_1: number (id) of a possible next point +next_path_2: number (id) of a possible next point +next_path_3: number (id) of a possible next point +next_path_4: number (id) of a possible next point +-------------------------------------------------------- + +*/ +void rider_path(void) +{ +} + +void riderpath_init(void) +{ +entity search,found; + + found = world; + search = find(world, classname, "rider_path"); + while(search != world && found == world) + { + if (search.path_id == 1) + found = search; + else + search = find(search, classname, "rider_path"); + } + + if (found==world) + { + dprint("No starting point for rider\n"); + remove(self); + return; + } + self.path_current=self.path_last = found; +} + +void riderpath_findnext(void) +{ + entity search,found; + float next,num_points,position; + + num_points = 0; + if (self.path_current.next_path_1) + num_points += 1; + if (self.path_current.next_path_2) + num_points += 1; + if (self.path_current.next_path_3) + num_points += 1; + if (self.path_current.next_path_4) + num_points += 1; + + if (!num_points) + { + dprintf("rider path %s has no next points\n",self.path_id); + remove(self); + return; + } + + position = random(num_points); +// dprintf("Num_points is %s ",num_points); +// dprintf("position is %s\n",position); + + num_points = next = 0; + if (self.path_current.next_path_1) + { + num_points += 1; + if (position <= num_points && !next) + next = self.path_current.next_path_1; + } + if (self.path_current.next_path_2) + { + num_points += 1; + if (position <= num_points && !next) + next = self.path_current.next_path_2; + } + + if (self.path_current.next_path_3) + { + num_points += 1; + if (position <= num_points && !next) + next = self.path_current.next_path_3; + } + + if (self.path_current.next_path_4) + { + num_points += 1; + if (position <= num_points && !next) + next = self.path_current.next_path_4; + } + + if (!next) + { + dprint("Internal error for rider path\n"); + dprintf(" Next is %s\n",next); + dprintf(" Num_points is %s\n",num_points); + dprintf(" position is %s\n",position); + return; + } + + found = world; + search = find(world, classname, "rider_path"); + while(search != world && found == world) + { + if (search.path_id == next) + found = search; + else + search = find(search, classname, "rider_path"); + } + + if (!found) + { + dprintf("Could not find rider path %s\n",next); + remove(self); + return; + } + else + self.path_current = found; + +} + +void rider_die(void); + +void riderpath_move(float move_speed) +{ +float distance, altitude, temp; +vector displace; +entity save_ent; + + if(self.velocity!='0 0 0') + self.velocity='0 0 0'; + + self.ideal_yaw = vectoyaw(self.path_current.origin - self.origin); + self.rider_last_y_change = self.rider_y_change; + self.rider_y_change = ChangeYaw(); + +//rj rider_die(); + + if (self.movetype == MOVETYPE_FLY) + { + distance = vhlen(self.origin - self.path_current.origin); + altitude = self.path_current.origin_z - self.origin_z; + + if (distance < 400) + { +// altitude *= 0.06; + temp = (distance - self.rider_path_distance) / (400-self.rider_path_distance); + temp = 1-temp; + temp = temp / 6; + + if (altitude > 30) + { + self.angles_x = temp * 200; + self.rider_move_adjustment -= 0.1; + } + else if (altitude < -30) + { + self.angles_x = 0 - (temp * 200); + self.rider_move_adjustment += 0.15; + } + + if (altitude > 60) + { + self.rider_move_adjustment -= 0.1; + } + else if (altitude < -60) + { + self.rider_move_adjustment += 0.15; + } + + altitude *= temp; + } + else + { + altitude = 0; + self.angles_x -= self.angles_x / 10; + self.rider_move_adjustment -= self.rider_move_adjustment / 15; + } +// dprintf("Move adjustment %s\n",self.rider_move_adjustment); + + self.origin_z += altitude; + +// altitude = self.path_current.origin_z - self.origin_z; +// dprintf("Flying: distance %s",distance); +// dprintf(" Alt is %s\n",altitude); + } + + move_speed += self.rider_move_adjustment; + + if(!walkmove(self.angles_y, move_speed, TRUE)) + { + save_ent=self.goalentity; + self.goalentity=self.path_current; + movetogoal(move_speed); + self.goalentity=save_ent; + } + + if (self.classname != "rider_famine") // Famine doesn't do radius pain + { + if (trace_ent)//!=world&&trace_ent.classname!="ghost") + { + displace = normalize(trace_ent.origin - self.origin); + if (infront(trace_ent)) + { + trace_ent.velocity += displace*random(1000,1600); + T_Damage (trace_ent, self, self, random(25,35)); + if(trace_ent.flags&FL_CLIENT) + { + trace_ent.punchangle_x = random(-9,-1); + trace_ent.punchangle_y = random(-10,10); + trace_ent.punchangle_z = random(-10,10); + } + } + else + { + trace_ent.velocity += displace*random(700,900); + T_Damage (trace_ent, self, self, random(15,20)); + if(trace_ent.flags&FL_CLIENT) + { + trace_ent.punchangle_x = random(-3,2); + trace_ent.punchangle_y = random(-5,5); + trace_ent.punchangle_z = random(-5,5); + } + } + } + } + + distance = vhlen(self.origin - self.path_current.origin); + if (distance < self.rider_path_distance) + riderpath_findnext(); +} + + + +void rider_multi_wait(void) +{ + if (self.max_health) + { + self.health = self.max_health; + self.takedamage = DAMAGE_NO_GRENADE; + self.solid = SOLID_BBOX; + } +} + +void rider_multi_trigger(void) +{ + if (self.nextthink > time) + { + return; // allready been triggered + } + if (self.enemy.classname != "rider_war") + { + return; + } + + if (random() <= self.rt_chance) + { + if (self.noise) sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + // don't trigger again until reset + self.takedamage = DAMAGE_NO; + + activator = self.enemy; + + SUB_UseTargets(); + } + + if (self.wait > 0) + { + self.think = rider_multi_wait; + thinktime self : self.wait; + } + else + { // we can't just remove (self) here, because this is a touch function + // called while C code is looping through area links... + self.touch = SUB_Null; + thinktime self : 0.1; + self.think = SUB_Remove; + } +} + + +void rider_multi_use(void) +{ + if (time < self.attack_finished) + return; + + self.enemy = activator; + rider_multi_trigger(); +} + +void rider_multi_touch(void) +{ + if (time < self.attack_finished) + return; + +// if the trigger has an angles field, check player's facing direction + + if (self.movedir != '0 0 0') + { + makevectors (other.angles); + if (v_forward * self.movedir < 0) + return; // not facing the right way + } + + self.enemy = other; + + rider_multi_trigger (); +} + +/*QUAKED rider_trigger_multiple (0.5 0.15 0) ? +-------------------------FIELDS------------------------- +rt_chance: chance (0-1) that the trigger will be run +-------------------------------------------------------- + +*/ +void rider_trigger_multiple(void) +{ + if (!self.wait) + self.wait = 0.2; + self.use = rider_multi_use; + + InitTrigger (); + + if (self.health) + { + self.max_health = self.health; + self.th_die = multi_killed; + self.takedamage = DAMAGE_NO_GRENADE; + self.solid = SOLID_BBOX; + setorigin (self, self.origin); // make sure it links into the world + } + else + { + self.touch = rider_multi_touch; + } +} + +/*QUAKED rider_trigger_once (0.5 0.15 0) ? +-------------------------FIELDS------------------------- +rt_chance: chance (0-1) that the trigger will be run +-------------------------------------------------------- + +*/ +void rider_trigger_once(void) +{ + self.wait = -1; + rider_trigger_multiple(); +} + + +void beam_move(void) +{ + thinktime self : HX_FRAME_TIME; + + if (self.scale < self.beam_max_scale) + self.scale += 0.6; + else + self.scale = self.beam_max_scale; + + if (self.beam_direction) + { + self.beam_angle_a += self.beam_speed; + if (self.beam_angle_a >= 360) self.beam_angle_a -= 360; + } + else + { + self.beam_angle_a -= self.beam_speed; + if (self.beam_angle_a < 0) self.beam_angle_a += 360; + } + + self.angles_x = cos(self.beam_angle_a) * self.beam_angle_b; + self.angles_z = sin(self.beam_angle_a) * self.beam_angle_b; +} + +void star_think(void) +{ + thinktime self : HX_FRAME_TIME; + + self.velocity = self.velocity * 1.05; + + if (self.scale < 2) + self.scale *= 1.08; +} + +void rider_star(void) +{ + entity star; + float angle; + + if (random() < 0.5) + return; + + star = spawn(); + + setmodel(star,"models/boss/star.mdl"); + setorigin(star,self.origin); + + setsize (star, '0 0 0', '0 0 0'); + star.owner = self.owner; + star.movetype = MOVETYPE_FLYMISSILE; + star.solid = SOLID_BBOX; + star.avelocity = randomv('40 40 40', '100 100 100'); + star.scale = 0.1; + + angle = random(360); + star.velocity_x = cos(angle)*300; + star.velocity_y = sin(angle)*300; + + star.classname = "rider_temp"; + star.think = star_think; + star.touch = SUB_Remove; + + thinktime star : HX_FRAME_TIME; +} + +void circle_think(void) +{ + thinktime self : HX_FRAME_TIME; + + rider_star(); + + if (self.monster_stage == 0) + { + self.scale *= 1.0275; + if (self.scale >= 2.5) + { + self.monster_stage = 1; + self.scale = 2.5; + } + } + else if (self.monster_stage == 1) + { + self.scale -= random(.1); + if (self.scale < 1.5 || random() < 0.1) + self.monster_stage = 2; + } + else if (self.monster_stage == 2) + { + self.scale += random(.1); + if (self.scale >= 2.5) + { + self.monster_stage = 1; + self.scale = 2.5; + } + else if (random() < 0.1) + self.monster_stage = 1; + } +} + +void rider_eol(void) +{ + entity search; + + if (self.count == 0) + { + self.count = 1; + self.effects (-) EF_BRIGHTLIGHT; + self.effects (+) EF_NODRAW; + if(self.movechain!=world) + self.movechain.effects (+) EF_NODRAW; + + thinktime self : 5; + + search = find(world, classname, "rider_temp"); + while (search != world) + { + remove(search); + search = find(search, classname, "rider_temp"); + } + + return; + } + +// return; + + nextmap = self.map; + nextstartspot = self.target; +//rj nextmap = "rick1"; + + intermission_running = 1; + + if (deathmatch) + intermission_exittime = time + 5; + else if (self.classname == "monster_eidolon") + intermission_exittime = time + 99999; + else + intermission_exittime = time + 2; + + + //Remove cross-level trigger server flags for next hub + serverflags(-)(SFL_CROSS_TRIGGER_1| + SFL_CROSS_TRIGGER_2| + SFL_CROSS_TRIGGER_3| + SFL_CROSS_TRIGGER_4| + SFL_CROSS_TRIGGER_5| + SFL_CROSS_TRIGGER_6| + SFL_CROSS_TRIGGER_7| + SFL_CROSS_TRIGGER_8); + + search=find(world,classname,"player"); + while(search) + {//Take away all their goodies + search.puzzle_inv1 = string_null; + search.puzzle_inv2 = string_null; + search.puzzle_inv3 = string_null; + search.puzzle_inv4 = string_null; + search.puzzle_inv5 = string_null; + search.puzzle_inv6 = string_null; + search.puzzle_inv7 = string_null; + search.puzzle_inv8 = string_null; + search=find(search,classname,"player"); + } + + WriteByte (MSG_ALL, SVC_INTERMISSION); + if (!cvar("registered") && cvar("oem")) + { + WriteByte (MSG_ALL, 9); + intermission_exittime = time + 99999; + } + else if (self.classname == "rider_famine") + WriteByte (MSG_ALL, 1); + else if (self.classname == "rider_death") + WriteByte (MSG_ALL, 2); + else if (self.classname == "rider_pestilence") + WriteByte (MSG_ALL, 3); + else if (self.classname == "rider_war") + WriteByte (MSG_ALL, 4); + else if (self.classname == "monster_eidolon") + WriteByte (MSG_ALL, 6); + else + dprint("Invalid boss creature\n"); + + FreezeAllEntities(); +} + +void rider_die(void) +{ +entity beam; +entity save; +entity found; +vector new_origin; + + if (self.think != rider_die) + { + SUB_UseTargets(); + + self.think = rider_die; + self.count = 0; + thinktime self : HX_FRAME_TIME; + self.rider_death_speed = 0.2; +// self.effects = EF_NODRAW; + + return; + } + + if (self.count == 0) + { + sound (self, CHAN_AUTO, "famine/flashdie.wav", 1, ATTN_NONE); // Start of the death flash + found=find(world,classname,"player"); + while(found) + {//Give them all the exp +// AwardExperience(found,self,self.experience_value); + found=find(found,classname,"player"); + } + self.experience_value=FALSE; + self.drawflags = self.drawflags | MLS_ABSLIGHT; + self.abslight = 3; + if(self.noise) + sound(self,CHAN_VOICE,self.noise,1,ATTN_NONE); + self.movetype=MOVETYPE_NONE; + self.velocity='0 0 0'; + } + + thinktime self : self.rider_death_speed; + self.rider_death_speed += 0.1; + + if (self.count >= 10) + { + if (self.count == 3) + { + beam = spawn(); + + new_origin = self.origin + '0 0 50'; + + setmodel(beam,"models/boss/circle.mdl"); + setorigin(beam,new_origin); + + setsize (beam, '0 0 0', '0 0 0'); + beam.owner = self; + beam.movetype = MOVETYPE_FLYMISSILE; + beam.solid = SOLID_NOT; + beam.drawflags = SCALE_TYPE_UNIFORM; + beam.scale = .1; + beam.skin = 0; + beam.avelocity = '0 0 300'; + beam.think = circle_think; + thinktime beam : HX_FRAME_TIME; + self.count = 13; + } + + self.count = 0; + self.think = rider_eol; + thinktime self : .5; + + return; + } + else + { + self.effects = EF_BRIGHTLIGHT; +// self.effects = EF_NODRAW; + + if (self.count == 3) + { + beam = spawn(); + + new_origin = self.origin + '0 0 50'; + + setmodel(beam,"models/boss/circle.mdl"); + setorigin(beam,new_origin); + + setsize (beam, '0 0 0', '0 0 0'); + beam.owner = self; + beam.movetype = MOVETYPE_FLYMISSILE; + beam.solid = SOLID_NOT; + beam.drawflags = SCALE_TYPE_UNIFORM; + beam.scale = .1; + beam.skin = 0; + beam.avelocity = '0 0 300'; + beam.classname = "rider_temp"; + beam.think = circle_think; + thinktime beam : HX_FRAME_TIME; + } + else if (self.count == 0) + { + starteffect(18, self.origin + '0 0 40'); + } + + } + + self.count += 1; + + beam = spawn(); + + makevectors(self.angles); +// new_origin = v_factorrange('-3 -25 45', '3 25 50') + self.origin; + new_origin = self.origin + '0 0 50'; + + setmodel(beam,"models/boss/shaft.mdl"); + setorigin(beam,new_origin); + + setsize (beam, '0 0 0', '0 0 0'); + beam.owner = self; + beam.drawflags = SCALE_ORIGIN_BOTTOM | SCALE_TYPE_XYONLY; + beam.movetype = MOVETYPE_FLYMISSILE; + beam.solid = SOLID_NOT; + beam.think = beam_move; + beam.angles = '0 0 0'; + beam.angles_x = random(-50,50); + beam.angles_z = random(-50,50); + beam.beam_angle_a = random(360); + beam.beam_angle_b = random(20,130); + beam.scale = .1; + beam.beam_max_scale = random(.5,1.5); + beam.classname = "rider_temp"; + if (random() > 0.5) + beam.beam_direction = 1; + + beam.beam_speed = random(2,4.5); + + save = self; + self = beam; + beam_move(); + self = save; +} + +void rider_use(void) +{ + thinktime self : 0.2; // wait for path points to spawn +} + +void rider_init(void) +{ + precache_model3 ("models/boss/shaft.mdl"); + precache_model3 ("models/boss/circle.mdl"); + precache_model3 ("models/boss/star.mdl"); + precache_sound3 ("famine/flashdie.wav"); + + total_monsters += 1; + + self.takedamage = DAMAGE_YES; + self.flags(+)FL_MONSTER; + self.flags2(+)FL_ALIVE; + self.thingtype=THINGTYPE_FLESH; + + if(self.classname!="monster_eidolon") + self.monsterclass=CLASS_BOSS; + + self.th_die = rider_die; + self.use = rider_use; + + if (!(self.spawnflags & 1)) + thinktime self : 0.2; // wait for path points to spawn +} diff --git a/rings.hc b/rings.hc new file mode 100644 index 0000000..bb0268f --- /dev/null +++ b/rings.hc @@ -0,0 +1,192 @@ +/* + * $Header: /HexenWorld/Siege/rings.hc 7 5/25/98 1:39p Mgummelt $ + */ +void player_fly(void); +void Ring_Init(string modelname,float name); + +void ring_touch (void) +{ + float amount; + entity holdself; + + if ((other.classname != "player") || (other.health <= 0)) + return; + + // Was it thrown out by player just a frame of two ago????? + if (self.owner == other && self.artifact_ignore_owner_time > time) + return; + if (self.artifact_ignore_time > time) + return; + + // take appropriate action + if ((self.classname == "Ring_Flight") && (deathmatch)) + { + if(other.cnt_flight > 4) + { + return; + } + } + + amount = random(); + if (amount < 0.5) + { + sprinti (other, PRINT_MEDIUM, STR_YOUPOSSESS); + sprinti (other, PRINT_MEDIUM, self.artifact_name); + } + else + { + sprinti (other, PRINT_MEDIUM, STR_YOUHAVEACQUIRED); + sprinti (other, PRINT_MEDIUM, self.artifact_name); + } + + sprint (other,PRINT_MEDIUM, "\n"); + + if ((deathmatch||(self.classname == "Ring_Flight"&&!self.owner))&&(self.artifact_respawn)) + { + self.mdl = self.model; + self.nextthink = time + 60; + self.think = SUB_regen; + } + + sound (other, CHAN_VOICE, "items/ringpkup.wav", 1, ATTN_NORM); + stuffcmd (other, "bf\n"); + self.solid = SOLID_NOT; + self.model = string_null; + + // take appropriate action + if ((self.classname == "Ring_Flight") && (deathmatch)) + { + other.cnt_flight += 1; + } + else if (self.classname == "Ring_Flight") + { + if(other.rings_active&RING_FLIGHT)//add time to current ring + { + other.ring_flight = 100; + other.ring_flight_time = time + 1; + } + else + { + other.rings(+)RING_FLIGHT; + other.ring_flight = 100; + other.ring_flight_time = time + 1; + holdself = self; + self = other; + player_fly(); + self = holdself; + other.rings_active (+) RING_FLIGHT; + } + other.rings_low (-) RING_FLIGHT; + } + else if (self.classname == "Ring_WaterBreathing") + { + other.rings = other.rings | RING_WATER; + other.ring_water = 100; + other.ring_water_time = time + 1; + + if (other.rings_low & RING_WATER) + other.rings_low (-) RING_WATER; + + } + else if (self.classname == "Ring_Turning") + { + other.rings = other.rings | RING_TURNING; + other.ring_turning = 100; + other.ring_turning_time = time + 1; + + other.rings_active (+) RING_TURNING; + + if (other.rings_low & RING_TURNING) + other.rings_low (-) RING_TURNING; + } + else if (self.classname == "Ring_Regeneration") + { + other.rings = other.rings | RING_REGENERATION; + other.ring_regeneration = 100; + other.rings_active (+) RING_REGENERATION; + + if (other.rings_low & RING_REGENERATION) + other.rings_low (-) RING_REGENERATION; + } + + activator = other; + SUB_UseTargets(); // fire all targets / killtargets + + if(!self.artifact_respawn) + { + remove(self); + } +} + +/*QUAKED Ring_WaterBreathing (0 0 0) (-8 -8 -44) (8 8 20) FLOATING +Ring of Water Breathing +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void Ring_WaterBreathing (void) +{ + if(self.origin=='600 -2088 156') + { + self.classname=="Climbing Boots"; + art_climb(); + } + else + { + precache_model("models/ringwb.mdl"); + Ring_Init("models/ringwb.mdl",STR_RINGWATERBREATHING); + } +} + +/*QUAKED Ring_Flight (0 0 0) (-8 -8 -44) (8 8 20) FLOATING +Ring of Flight +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void Ring_Flight (void) +{ + precache_model("models/ringft.mdl"); + Ring_Init("models/ringft.mdl",STR_RINGFLIGHT); +} + +/*QUAKED Ring_Regeneration (0 0 0) (-8 -8 -44) (8 8 20) FLOATING +Ring of Regeneration +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void Ring_Regeneration (void) +{ + precache_model("models/ringre.mdl"); + Ring_Init("models/ringre.mdl",STR_RINGREGENERATION); +} + +/*QUAKED Ring_Turning (0 0 0) (-8 -8 -44) (8 8 20) FLOATING +Ring of Turning +-------------------------FIELDS------------------------- +None +-------------------------------------------------------- +*/ +void Ring_Turning (void) +{ + precache_model("models/ringtn.mdl"); + Ring_Init("models/ringtn.mdl",STR_RINGTURNING); +} + +void Ring_Init(string modelname,float name) +{ + setmodel(self, modelname); + + self.netname = "Ring"; + self.artifact_name = name; + + self.artifact_respawn = deathmatch; + + setsize(self,'0 0 0','0 0 0'); + self.hull=HULL_POINT; + self.touch = ring_touch; + + StartItem(); +} + diff --git a/scorpion.hc b/scorpion.hc new file mode 100644 index 0000000..81b4e1a --- /dev/null +++ b/scorpion.hc @@ -0,0 +1,745 @@ + +//************************************************************************** +//** +//** scorpion.hc +//** bgokey +//** +//** $Header: /HexenWorld/Siege/scorpion.hc 3 5/25/98 1:39p Mgummelt $ +//** +//************************************************************************** + +// FRAMES ------------------------------------------------------------------ + +// Attack 1 (claw and tail) +$frame ScAttA1 ScAttA2 ScAttA3 ScAttA4 ScAttA5 +$frame ScAttA6 ScAttA7 ScAttA8 ScAttA9 ScAttA10 +$frame ScAttA11 ScAttA12 ScAttA13 ScAttA14 ScAttA15 +$frame ScAttA16 ScAttA17 ScAttA18 ScAttA19 ScAttA20 +$frame ScAttA21 ScAttA22 ScAttA23 ScAttA24 ScAttA25 + +// Attack 2 (claw only) +$frame ScAttB1 ScAttB2 ScAttB3 ScAttB4 ScAttB5 +$frame ScAttB6 ScAttB7 ScAttB8 ScAttB9 ScAttB10 +$frame ScAttB11 ScAttB12 ScAttB13 ScAttB14 ScAttB15 +$frame ScAttB16 ScAttB17 ScAttB18 ScAttB19 ScAttB20 +$frame ScAttB21 ScAttB22 ScAttB23 ScAttB24 ScAttB25 +$frame ScAttB26 ScAttB27 + +// Attack 3 (tail only) +$frame ScAttC1 ScAttC2 ScAttC3 ScAttC4 ScAttC5 +$frame ScAttC6 ScAttC7 ScAttC8 ScAttC9 ScAttC10 +$frame ScAttC11 ScAttC12 ScAttC13 ScAttC14 ScAttC15 +$frame ScAttC16 ScAttC17 ScAttC18 ScAttC19 ScAttC20 +$frame ScAttC21 ScAttC22 + +// Death +$frame SCDead1 SCDead2 SCDead3 SCDead4 SCDead5 +$frame SCDead6 SCDead7 SCDead8 SCDead9 SCDead10 +$frame SCDead11 SCDead12 SCDead13 SCDead14 SCDead15 +$frame SCDead16 SCDead17 SCDead18 SCDead19 SCDead20 +$frame SCDead21 + +// Pain +$frame ScPain1 ScPain2 ScPain3 ScPain4 ScPain5 +$frame ScPain6 ScPain7 ScPain8 ScPain9 ScPain10 + +// Transition from standing to attack pose +$frame ScRedy1 ScRedy2 ScRedy3 ScRedy4 ScRedy5 +$frame ScRedy6 ScRedy7 ScRedy8 ScRedy9 ScRedy10 +$frame ScRedy11 + +// Transition from standing to walk +$frame ScStep1 ScStep2 ScStep3 ScStep4 + +// Transition from walk to standing +$frame ScStop1 ScStop2 ScStop3 ScStop4 ScStop5 +$frame ScStop6 ScStop7 ScStop8 ScStop9 + +// Wake from resting (ScWake1 = resting) +$frame ScWake1 ScWake2 ScWake3 ScWake4 ScWake5 +$frame ScWake6 ScWake7 ScWake8 ScWake9 ScWake10 +$frame ScWake11 ScWake12 ScWake13 ScWake14 ScWake15 +$frame ScWake16 ScWake17 ScWake18 ScWake19 ScWake20 +$frame ScWake21 ScWake22 ScWake23 ScWake24 ScWake25 +$frame ScWake26 ScWake27 ScWake28 ScWake29 ScWake30 + +// Walk +$frame ScWalk1 ScWalk2 ScWalk3 ScWalk4 ScWalk5 +$frame ScWalk6 ScWalk7 ScWalk8 ScWalk9 ScWalk10 +$frame ScWalk11 ScWalk12 ScWalk13 ScWalk14 ScWalk15 +$frame ScWalk16 + +// CONSTANTS --------------------------------------------------------------- + +float SCORPION_YELLOW = 0; +float SCORPION_BLACK = 1; + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +void ScorpionInit(float type); +void ScorpionStand(void); +void ScorpionWake(void); +void ScorpionWalk(void); +void ScorpionRun(void); +void ScorpionRunBlack(void); +void ScorpionPainDecide(void); +void ScorpionPain(void); +void ScorpionMeleeDecide(void); +void ScorpionMelee1(void); +void ScorpionMelee2(void); +void ScorpionMelee3(void); +void ScorpionMelee4(void); +void ScorpionDie(void); +void ScorpionDieInit(void); +entity ScorpionLookProjectiles(void); +float ScorpionCheckDefense(void); +void ScorpionStrafeDefense(void); + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +float ScorpionStandFrames[6] = +{ + $scwake1, $scwake2, $scwake3, $scwake4, $scwake3, $scwake2 +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// monster_scorpion_yellow +// +//========================================================================== +/*QUAKED monster_scorpion_yellow (1 0.3 0) (-10 -10 0) (10 10 64) AMBUSH +Yellow scorpion. +------- key / value ---------------------------- +health = 100 +experience_value = 60 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_scorpion_yellow(void) +{ + ScorpionInit(SCORPION_YELLOW); +} + +//========================================================================== +// +// monster_scorpion_black +// +//========================================================================== +/*QUAKED monster_scorpion_black (1 0.3 0) (-10 -10 0) (10 10 64) AMBUSH +Black scorpion. +------- key / value ---------------------------- +health = 200 +experience_value = 150 +------- spawnflags ----------------------------- +AMBUSH +*/ + +void monster_scorpion_black(void) +{ + ScorpionInit(SCORPION_BLACK); +} + +//========================================================================== +// +// ScorpionInit +// +//========================================================================== + +void ScorpionInit(float type) +{ + if(deathmatch) + { + remove(self); + return; + } + + if not(self.flags2&FL_SUMMONED) + { + precache_model2("models/scorpion.mdl"); + + precache_sound2("scorpion/awaken.wav"); + precache_sound2("scorpion/walk.wav"); + precache_sound2("scorpion/clawsnap.wav"); + precache_sound2("scorpion/tailwhip.wav"); + precache_sound2("scorpion/pain.wav"); + precache_sound2("scorpion/death.wav"); + } + setmodel(self, "models/scorpion.mdl"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + self.thingtype = THINGTYPE_FLESH; + + if (type == SCORPION_YELLOW) + self.yaw_speed = 8; + else + self.yaw_speed = 10; + + self.mass = 9; + self.mintel = 4; + + //self.touch = SUB_Null; + //self.use = SUB_Null; + setsize(self, '-16 -16 0', '16 16 64'); + + if(type == SCORPION_YELLOW) + { + self.health = 100; + self.experience_value = 60; + } + else + { + self.health = 200; + self.experience_value = 150; + } + + self.takedamage = DAMAGE_YES; + + self.th_stand = ScorpionStand; + self.th_walk = ScorpionWalk; + + if(type == SCORPION_BLACK) + self.th_run = ScorpionRunBlack; + else + self.th_run = ScorpionRun; + + self.th_melee = ScorpionMeleeDecide; + self.th_pain = ScorpionPainDecide; + self.th_die = ScorpionDieInit; + + self.view_ofs = '0 0 12'; + + self.scorpionType = type; + if(type == SCORPION_BLACK) + { + self.skin = 1; + } + walkmonster_start(); +} + +//========================================================================== +// +// ScorpionStand +// +//========================================================================== + +void ScorpionStand(void) +{ + self.think = ScorpionStand; + self.nextthink = time + 0.2; + self.scorpionRest += 2; + if(self.scorpionRest < 0 || self.scorpionRest > 5) + { + self.scorpionRest = 0; + } + self.frame = ScorpionStandFrames[self.scorpionRest]; + ai_stand(); + if(self.think != ScorpionStand) + { // Wake up + self.th_save = self.think; + self.think = ScorpionWake; + sound(self, CHAN_VOICE, "scorpion/awaken.wav", 1, ATTN_NORM); + } +} + +//========================================================================== +// +// ScorpionWake +// +//========================================================================== + +void ScorpionWake(void) [++ $scwake1..$scwake30] +{ + if(cycle_wrapped) + { + self.cnt = time; + self.think = self.th_save; + self.think(); + } +} + +//========================================================================== +// +// ScorpionWalk +// +//========================================================================== + +void ScorpionWalk(void) [++ $scwalk1..$scwalk16] +{ + if(((self.scorpionWalkCount += 1)&3) == 0) + { + sound(self, CHAN_BODY, "scorpion/walk.wav", random(0.9, 1), ATTN_NORM); + } + ai_walk(2); + if(random()<0.1) + pitch_roll_for_slope('0 0 0'); +} + +//========================================================================== +// +// ScorpionRunBlack +// +//========================================================================== + +void ScorpionRunBlack(void) [++ $scwalk1..$scwalk16] +{ + float enemy_dist; + + if(((self.scorpionWalkCount += 1)&3) == 0) + { + sound(self, CHAN_BODY, "scorpion/walk.wav", random(0.9, 1), ATTN_NORM); + } + + if ((self.enemy.last_attack > time - 1) && (fov(self, self.enemy, 45))) + { + if (ScorpionCheckDefense()) + { + ScorpionStrafeDefense(); + return; + } + } + + if (self.attack_state == AS_SLIDING) + if ((random() < 0.8) && (self.cnt <= time)) + { + self.cnt = time + random(0.5, 1.0); + self.attack_state = AS_STRAIGHT; + ScorpionMelee4(); + return; + } + + enemy_dist = vlen(self.enemy.origin - self.origin); + + if (enemy_dist < 120) + { + if ((random() < 0.33) && (infront(self.enemy)) && (self.cnt <= time)) + { + self.attack_state = AS_SLIDING; + + self.cnt = time + random(0.5, 1.0); + self.lefty = random(0,1); + if (self.lefty < 0.5) self.lefty = 0; + else self.lefty = 1; + + ai_run(10); + return; + } + else if (!infront(self.enemy)) + self.attack_state = AS_STRAIGHT; + } + else self.attack_state = AS_STRAIGHT; + + ai_run(8); + if(random()<0.1) + pitch_roll_for_slope('0 0 0'); +} + +//========================================================================== +// +// ScorpionRun +// +//========================================================================== + +void ScorpionRun(void) [++ $scwalk1..$scwalk16] +{ + float enemy_dist; + + if(((self.scorpionWalkCount += 1)&3) == 0) + { + sound(self, CHAN_BODY, "scorpion/walk.wav", random(0.9, 1), ATTN_NORM); + } + + + if ((self.enemy.last_attack > time - 1) && (fov(self, self.enemy, 45))) + { + if (ScorpionCheckDefense()) + { + ScorpionStrafeDefense(); + return; + } + } + + if (self.attack_state == AS_SLIDING) + if ((random() < 0.5) && (self.cnt <= time)) + { + self.cnt = time + random(0.5, 1.0); + self.attack_state = AS_STRAIGHT; + ScorpionMelee4(); + return; + } + + enemy_dist = vlen(self.enemy.origin - self.origin); + + if (enemy_dist < 120) + { + if ((random() < 0.33) && (infront(self.enemy)) && (self.cnt <= time)) + { + self.attack_state = AS_SLIDING; + + self.cnt = time + random(0.5, 1.0); + self.lefty = random(0,1); + if (self.lefty < 0.5) self.lefty = 0; + else self.lefty = 1; + + ai_run(10); + return; + } + else if (!infront(self.enemy)) + self.attack_state = AS_STRAIGHT; + } + else self.attack_state = AS_STRAIGHT; + + ai_run(6); + if(random()<0.1) + pitch_roll_for_slope('0 0 0'); +} +//========================================================================== +// +// ScorpionPainDecide +// +//========================================================================== + +void ScorpionPainDecide(void) +{ + if(random() < 0.3) + { + ScorpionPain(); + sound(self, CHAN_VOICE, "scorpion/pain.wav", 1, ATTN_NORM); + } +} + +//========================================================================== +// +// ScorpionPain +// +//========================================================================== + +void ScorpionPain(void) [++ $scpain1..$scpain10] +{ + if(cycle_wrapped) + { + self.th_run(); + } +} + +//========================================================================== +// +// ScorpionMelee +// +//========================================================================== +void ScorpionMelee(float damage) +{ + vector source; + + makevectors (self.angles); + source = self.origin; + traceline (source, source + v_forward*60, FALSE, self); + + if (trace_ent != self.enemy) return; + + damage += random(0.1, 1); + T_Damage (self.enemy, self, self, damage); +} + +//========================================================================== +// +// ScorpionMeleeDecide +// +//========================================================================== + +void ScorpionMeleeDecide(void) +{ + float r; + + r = random(); + self.last_attack=time; + if (self.classname == "monster_scorpion_black") + { + if(r < 0.2) + { + ScorpionMelee1(); + } + else if(r < 0.4) + { + ScorpionMelee2(); + } + else if (r < 0.6) + { + ScorpionMelee3(); + } + else + ScorpionMelee4(); + } + else + { + if(r < 0.3) + { + ScorpionMelee1(); + } + else if(r < 0.6) + { + ScorpionMelee2(); + } + else if (r < 0.9) + { + ScorpionMelee3(); + } + else + ScorpionMelee4(); + } +} + +//========================================================================== +// +// ScorpionMelee1 +// +//========================================================================== + +void ScorpionMelee1(void) [++ $scatta1..$scatta25] +{ + if(self.frame == $scatta4 || self.frame == $scatta9) + { + sound(self, CHAN_VOICE, "scorpion/clawsnap.wav", 1, ATTN_NORM); + ScorpionMelee(1); + } + else if(self.frame == $scatta14) + { + sound(self, CHAN_BODY, "scorpion/tailwhip.wav", 1, ATTN_NORM); + ScorpionMelee(1); + } + + if(self.frame > $scatta16 && self.frame < $scatta20) + { + ai_charge(4); + if (self.classname == "monster_scorpion_yellow") + ScorpionMelee(2); + else + ScorpionMelee(3); + } + else + { + ai_charge(2); + } + + if(cycle_wrapped) + self.think = self.th_run; +} + +//========================================================================== +// +// ScorpionMelee2 +// +//========================================================================== + +void ScorpionMelee2(void) [++ $scattb1..$scattb27] +{ + if(self.frame == $scattb4 || self.frame == $scattb8 + || self.frame == $scattb13) + { + sound(self, CHAN_VOICE, "scorpion/clawsnap.wav", 1, ATTN_NORM); + ScorpionMelee(1); + } + + if(self.frame > $scattb16 && self.frame < $scattb20) + { + ai_charge(4); + if (self.classname == "monster_scorpion_yellow") + ScorpionMelee(2); + else + ScorpionMelee(3); + } + else + { + ai_charge(2); + } + if(cycle_wrapped) + self.think = self.th_run; +} + +//========================================================================== +// +// ScorpionMelee3 +// +//========================================================================== + +void ScorpionMelee3(void) [++ $scattc1..$scattc22] +{ + if(self.frame == $scattc9) + { + sound(self, CHAN_BODY, "scorpion/tailwhip.wav", 1, ATTN_NORM); + ScorpionMelee(1); + } + + if(self.frame > $scattc16 && self.frame < $scattc20) + { + ai_charge(4); + if (self.classname == "monster_scorpion_yellow") + ScorpionMelee(2); + else + ScorpionMelee(3); + } + else + { + ai_charge(2); + } + if(cycle_wrapped) + self.think = self.th_run; +} + +//========================================================================== +// +// ScorpionMelee4 +// +//========================================================================== + +void ScorpionMelee4(void) [++ $scatta1..$scatta25] +{ + if (self.frame == $scatta4 || self.frame == $scatta9) + { + sound(self, CHAN_VOICE, "scorpion/clawsnap.wav", 1, ATTN_NORM); + ScorpionMelee(1); + } + else if(self.frame == $scatta14) + { + sound(self, CHAN_BODY, "scorpion/tailwhip.wav", 1, ATTN_NORM); + if (self.classname == "monster_scorpion_yellow") + ScorpionMelee(2); + else + ScorpionMelee(3); + } + + if(self.frame > $scatta16 && self.frame < $scatta20) + { + ai_charge(16); + if (self.classname == "monster_scorpion_yellow") + ScorpionMelee(2); + else + ScorpionMelee(4); + } + else + { + ai_charge(12); + } + if(cycle_wrapped) + self.think = self.th_run; +} + +//========================================================================== +// +// ScorpionStrafeDefense +// +//========================================================================== + +void ScorpionStrafeDefense(void) [++ $scwalk1..$scwalk8] +{ + float ofs; + + if (cycle_wrapped) + { + thinktime self : 0.1; + self.think = self.th_run; + return; + } + + makevectors(self.v_angle); + + if (self.lefty == -1) + ofs = 90; + else + ofs = -90; + + if (walkmove (self.ideal_yaw + ofs, 10, FALSE)) + return; + + walkmove (self.ideal_yaw - ofs, 10, FALSE); + if (self.lefty == -1) + self.lefty = 1; + else self.lefty = -1; +} + + +//========================================================================== +// +// ScorpionCheckDefense +// +//========================================================================== + +float ScorpionCheckDefense() +{ + entity enemy_proj; + float r; + + enemy_proj=ScorpionLookProjectiles(); + + if (!enemy_proj) return 0; + + r=range(enemy_proj); + + self.lefty=check_heading_left_or_right(enemy_proj); + + if(r==RANGE_NEAR) + { + if (random() < 0.2) + return 1; + } + return 0; +} + +//========================================================================== +// +// ScorpionLookProjectiles +// +//========================================================================== +entity ScorpionLookProjectiles () +{ + entity found, enemy_proj; + + found=findradius(self.origin,1000); + while(found) + { + if(found.movetype==MOVETYPE_FLYMISSILE||found.movetype==MOVETYPE_BOUNCE||found.movetype==MOVETYPE_BOUNCEMISSILE) + if(visible(found)) + { + if(heading(self,found,0.9)) + enemy_proj=found; + } + found=found.chain; + } + if(enemy_proj) + return enemy_proj; + else + return world; +} + +//========================================================================== +// +// ScorpionDie +// +//========================================================================== + + +void ScorpionDie(void) +{ + if(self.frame == $scdead21) + { + MakeSolidCorpse(); + return; + } + + + if(self.health < -30) + { + chunk_death(); + } + + self.frame += 1; + thinktime self : HX_FRAME_TIME; +} + +void ScorpionDieInit(void) [$scdead1 ScorpionDie] +{ + sound(self, CHAN_VOICE, "scorpion/death.wav", 1, ATTN_NORM); +} diff --git a/setmodth.hc b/setmodth.hc new file mode 100644 index 0000000..c772ffe --- /dev/null +++ b/setmodth.hc @@ -0,0 +1,126 @@ +//In progs.src, must come AFTER all player.hc's + + +void() SetModelAndThinks = +{//MG +//Note: you'll also want to set a head model +//for each. + + self.touch=PlayerTouch; + self.th_die=PlayerDie; + self.th_goredeath=player_frames_behead; + self.th_pain=player_pain; + self.experience=350000; + self.level=6; + self.flags2(-)FL2_FIRERESIST;//WHY? + if(self.playerclass==CLASS_ASSASSIN) + { + self.items(+)IT_WEAPON2|IT_WEAPON3|IT_WEAPON4; + self.mass=6;//should be 15 + + Ass_Change_Weapon(); //sets other th_*'s based on weapon in hand + + setmodel (self, "models/assassin.mdl"); + self.headmodel="models/h_ass.mdl"; + if(self.weapon==IT_WEAPON4) + self.th_weapon=grenade_select; + else if(self.weapon==IT_WEAPON2||self.weapon==IT_WEAPON3) + self.th_weapon=crossbow_select; + else + self.th_weapon=punchdagger_select; + self.armor_breastplate = 20; + } + else if(self.playerclass==CLASS_SUCCUBUS) + { + self.mass=7; + + self.items(+)IT_WEAPON2|IT_WEAPON3|IT_WEAPON4|IT_WEAPON5|IT_WEAPON6|IT_WEAPON7|IT_WEAPON8; + self.flags2(+)FL2_FIRERESIST; + + Suc_Change_Weapon(); //sets other th_*'s based on weapon in hand + + setmodel (self, "models/succubus.mdl"); + self.headmodel="models/h_suc.mdl"; + if(self.weapon==IT_WEAPON4) + self.th_weapon=grenade_select; + else if(self.weapon==IT_WEAPON2) + self.th_weapon=vorpal_select; + else if(self.weapon==IT_WEAPON3) + self.th_weapon=crossbow_select; + else if(self.weapon==IT_WEAPON1) + self.th_weapon=bloodrain_select; + else + self.th_weapon=flameorb_select; + self.armor_amulet = self.armor_bracer = 20; + } + else if(self.playerclass==CLASS_CRUSADER) + { + self.mass=7;//should be 10 + setmodel (self, "models/crusader.mdl"); + self.headmodel="models/h_cru.mdl"; + + Cru_Change_Weapon(); + if(self.weapon==IT_WEAPON1) + self.th_weapon=warhammer_select; + else + self.th_weapon=icestaff_select; + self.items(+)IT_WEAPON2|IT_WEAPON3|IT_WEAPON4|IT_WEAPON5|IT_WEAPON6|IT_WEAPON7|IT_WEAPON8; + self.armor_bracer = self.armor_breastplate = self.armor_helmet = 20; + } + else if(self.playerclass==CLASS_PALADIN) + { + self.items(+)IT_WEAPON2|IT_WEAPON3; + self.mass=8;//should be 15 + Pal_Change_Weapon(); //sets other th_*'s based on weapon in hand + + setmodel (self, "models/paladin.mdl"); + self.headmodel="models/h_pal.mdl"; + + if(self.weapon==IT_WEAPON3) + self.th_weapon=crossbow_select; + else if(self.weapon==IT_WEAPON2) + self.th_weapon=axe_select; + else + self.th_weapon=vorpal_select; + self.armor_amulet = self.armor_bracer = self.armor_breastplate = self.armor_helmet = 20; + } + else if(self.playerclass==CLASS_NECROMANCER) + { + self.mass=7;//should be 10 + setmodel (self, "models/necro.mdl"); + self.headmodel="models/h_nec.mdl"; + + Nec_Change_Weapon(); //sets other th_*'s based on weapon in hand + + if(self.weapon==IT_WEAPON1) + self.th_weapon=sickle_select; + else if(self.weapon==IT_WEAPON2) + self.th_weapon=crossbow_select; + else + self.th_weapon=magicmis_select; + self.items(+)IT_WEAPON2|IT_WEAPON3|IT_WEAPON4|IT_WEAPON5|IT_WEAPON6|IT_WEAPON7|IT_WEAPON8; + } + if(self.playerclass==CLASS_DWARF) + { + self.items(+)IT_WEAPON2; + self.mass=4;//should be 15 + Dwf_Change_Weapon(); //sets other th_*'s based on weapon in hand + + setmodel (self, "models/hank.mdl"); + self.headmodel="models/h_hank.mdl"; + + if(self.weapon==IT_WEAPON2) + self.th_weapon=axe_select; + else + self.th_weapon=warhammer_select; + self.armor_amulet = self.armor_bracer = self.armor_breastplate = self.armor_helmet = 20; + setsize(self,'-16 -16 0','16 16 28'); + self.hull=HULL_CROUCH; + } + else + setsize(self,'-16 -16 0','16 16 56'); + self.init_model=self.model; + self.flags(+)FL_SPECIAL_ABILITY1; + self.flags(+)FL_SPECIAL_ABILITY2; +}; + diff --git a/setstaff.hc b/setstaff.hc new file mode 100644 index 0000000..23ff63c --- /dev/null +++ b/setstaff.hc @@ -0,0 +1,842 @@ +/* + * $Header: /HexenWorld/Siege/setstaff.hc 33 5/25/98 1:39p Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\weapons\setstaff\newstff\scarabst.hc + +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\weapons\setstaff\newstff +$origin 0 0 0 +$base BASE skin +$skin skin +$skin SKIN2 +$flags 0 + +// +$frame build1 build2 build3 build4 build5 +$frame build6 build7 build8 build9 build10 +$frame build11 build12 build13 build14 build15 + +// +$frame chain1 chain2 chain3 chain4 chain5 +$frame chain6 chain7 chain8 chain9 + +// +$frame rootpose + +// +$frame scarab1 scarab2 scarab3 scarab4 scarab5 +$frame scarab6 scarab7 + +// +$frame select1 select2 select3 select4 select5 +$frame select6 select7 select8 select9 select10 +$frame select11 select12 + + + +void setstaff_decide_attack (void); +void setstaff_idle (void); + +void() DeactivateGhook =//don't worry about the effect--it'll get rid of itself +{ + self.aflag=FALSE; + + remove(self); +}; + +void PullBack (void) +{ + if(self.enemy!=world) + { + if(self.enemy.flags2&FL_ALIVE) + { + if (self.enemy.flags&FL_CLIENT) + { + if(!(self.enemy.rings&RING_FLIGHT)) + self.enemy.movetype=MOVETYPE_WALK; + } + else + { + if (!(self.enemy.flags & FL_FLY)) + self.enemy.movetype = MOVETYPE_STEP; +// self.enemy.movetype = self.enemy.oldmovetype; + } + } + else + { + self.enemy.movetype=MOVETYPE_BOUNCE; + } + self.enemy.velocity_z-=100; + self.enemy.flags2(-)FL_CHAINED; + self.enemy=world; + } + + self.movetype=MOVETYPE_NOCLIP; + self.solid=SOLID_NOT; + self.velocity=normalize(self.view_ofs-self.origin)*350; + self.flags(-)FL_ONGROUND; + if(vlen(self.origin-self.view_ofs)<48||self.lifetime 100 ) + dir = dir*300; + if(self.enemy.flags&FL_ONGROUND) + { + self.enemy.flags(-)FL_ONGROUND; + dir+='0 0 200'; + } + if(self.enemy.flags&FL_CLIENT) + self.enemy.adjust_velocity=(self.enemy.velocity+dir)*0.5; + else + self.enemy.velocity = (self.enemy.velocity+dir)*0.5; + } + else + self.enemy.velocity='0 0 0'; + + if(!self.enemy.health||!self.enemy.flags2&FL_ALIVE||!self.enemy.flags2&FL_CHAINED||self.attack_finished150||(other.flags&FL_MONSTER&&other.monsterclass>=CLASS_BOSS)) + { + self.lockentity=other; + scarab_die(); + } + else + { + self.touch=SUB_Null; + self.velocity='0 0 0'; + self.enemy=other; + ChainsOfLove(); + } + } + else + scarab_die(); +//*/ +} + +void scarab_think () +{ + self.frame+=1; + if(self.frame>15) + self.frame=8; + + if (self.movechain) + { + self.movechain.frame=self.frame; + } + + if(self.pain_finished<=time) + { + HomeThink(); + self.angles=vectoangles(self.velocity); + self.pain_finished=time+0.1; + } + + if(self.lifetime300) + DarkExplosion(); + else if(other!=self.nextbolt) + { + if(other.takedamage) + { + self.nextbolt=other; + makevectors(self.velocity); + T_Damage(other,self,self.owner,self.dmg); + if(self.dmg<10) + { + T_Damage(other,self,self.owner,10); + DarkExplosion(); + } + else + { + //fixme: add to effect +// if(other.thingtype==THINGTYPE_FLESH) +// { +// MeatChunks(self.origin+v_forward*36, self.velocity*0.2+v_right*random(-30,150)+v_up*random(-30,150),5,other); +// } + + ttype = GetImpactType(other); + + updateeffect(self.xbo_effect_id, CE_HWDRILLA, 0, self.origin, ttype); + + if(other.classname=="player") + T_Damage(other,self,self.owner,(self.dmg+self.frags*10)/3); + else + T_Damage(other,self,self.owner,self.dmg+self.frags*10); + self.frags+=1; + self.dmg-=10; + } + } + } +} + +void pincer_think () +{ + if(self.frame<7) + self.frame+=1; + if(self.pain_finished<=time) + { + self.pain_finished=time+1; + } + + if(self.lifetime=$build2)&&(self.weaponframe<=$build15)) + { + stopSound(self,CHAN_UPDATE);//weapon_sound(self, "misc/null.wav"); + self.effects(-)EF_UPDATESOUND; + self.t_width=SOUND_STOPPED; + } + makevectors(self.v_angle); + self.punchangle_x=power_value*-1; + self.effects(+)EF_MUZZLEFLASH; + newmis = spawn(); + newmis.owner = self; + newmis.enemy = world; + newmis.nextbolt = world; + newmis.classname="pincer"; + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.solid=SOLID_PHASE; + newmis.thingtype=1; + newmis.touch=pincer_touch; + newmis.dmg=power_value*17; + if(newmis.dmg<33) + newmis.dmg=33; + newmis.th_die=DarkExplosion; + + newmis.drawflags=MLS_ABSLIGHT; + newmis.abslight=0.5; + newmis.scale=2; + + newmis.speed=750+30*power_value; + newmis.movedir=v_forward; + newmis.velocity=newmis.movedir*newmis.speed; + newmis.angles=vectoangles(newmis.velocity); + +// setmodel(newmis,"models/scrbstp1.mdl"); + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,self.origin+self.proj_ofs+v_forward*8); + + newmis.xbo_effect_id = starteffect(CE_HWDRILLA, newmis.origin, self.v_angle, newmis.speed); + + self.attack_finished = time + power_value/10 + 0.5; + newmis.lifetime=time+7; + newmis.think=pincer_think; + thinktime newmis : 0; +} + +/* +============================================= +WEAPON MODEL CODE +============================================= +*/ +void setstaff_powerfire (void) +{ + self.wfs = advanceweaponframe($scarab1,$scarab7); + self.th_weapon = setstaff_powerfire; + if (self.weaponframe== $scarab2) + { + TheOldBallAndChain(); + self.greenmana -= 30; + self.bluemana -= 30; + } + + if (self.wfs == WF_CYCLE_WRAPPED) + setstaff_idle(); +} + +void setstaff_settle2 () +{ + self.effects(-)EF_MUZZLEFLASH; + self.wfs = advanceweaponframe($chain1,$chain9); + self.th_weapon = setstaff_settle2; + + if (self.wfs == WF_LAST_FRAME) + setstaff_idle(); +} + +void setstaff_settle () +{ + self.wfs = advanceweaponframe($chain1,$chain9); + self.th_weapon = setstaff_settle2;//after a frame, turn off light + + if (self.wfs == WF_LAST_FRAME) + setstaff_idle(); +} + +void setstaff_readyfire (void) +{ + if(self.weaponframe>$build15) + self.weaponframe=$build1; + + if(self.weaponframe==$build2) + { + //weapon_sound(self, "assassin/build.wav"); + sound(self, CHAN_UPDATE+PHS_OVERRIDE_R,"assassin/build.wav",1,ATTN_LOOP); + self.effects(+)EF_UPDATESOUND; + } + + + if (self.weaponframe >= $build1 && self.weaponframe < $build15) + { +// updateSoundPos(self,CHAN_WEAPON);//FIXME: make this built into client sound code- maybe some sort of flag or field? + self.weaponframe_cnt +=1; + if (self.weaponframe_cnt > 3) + { + self.wfs = advanceweaponframe($build1,$build15); + self.weaponframe_cnt =0; + } + else if(self.weaponframe_cnt==1) + { + if (self.weaponframe == $build1) + { + self.greenmana-=3; + if(self.greenmana<0) + self.greenmana=0; + + self.bluemana-=3; + if(self.bluemana<0) + self.bluemana=0; + } + else + { + if(self.greenmana>=1) + self.greenmana-=1; + if(self.bluemana>=1) + self.bluemana-=1; + } + } + if(self.weaponframe==$build15) + self.weaponframe_cnt=time+0.8; + } + else if(self.weaponframe_cnt=10) + self.greenmana-=10; + else + self.button0=FALSE; + if(self.bluemana>=10) + self.bluemana-=10; + else + self.button0=FALSE; + } + + self.th_weapon = setstaff_readyfire; + + if(!self.button0||self.greenmana<=0||self.bluemana<=0) + { + self.t_width=FALSE; + self.weaponframe_cnt=0; + Drilla(14 - ($build15 - self.weaponframe)); + setstaff_settle(); + } +} + +void() ass_setstaff_fire = +{ + if (self.artifact_active & ART_TOMEOFPOWER) // Pause for firing in power up mode + self.th_weapon=setstaff_powerfire; + else + self.th_weapon=setstaff_readyfire; + + thinktime self : 0; + self.nextthink=time; +}; + + +void setstaff_idle (void) +{ + self.effects(-)EF_MUZZLEFLASH; + self.weaponframe=$rootpose; + self.th_weapon=setstaff_idle; +} + + +void setstaff_select (void) +{ + self.wfs = advanceweaponframe($select12,$select1); + self.weaponmodel = "models/scarabst.mdl"; + self.th_weapon=setstaff_select; + self.last_attack=time; + + if (self.wfs == WF_LAST_FRAME) + { + self.attack_finished = time - 1; + setstaff_idle(); + } +} + +void setstaff_deselect (void) +{ + self.effects(-)EF_MUZZLEFLASH; + self.wfs = advanceweaponframe($select1,$select12); + self.th_weapon=setstaff_deselect; + if (self.wfs == WF_LAST_FRAME) + W_SetCurrentAmmo(); +} + +void setstaff_decide_attack (void) +{ + self.attack_finished = time + 0.5; +} + diff --git a/shalrath.hc b/shalrath.hc new file mode 100644 index 0000000..fbb9a18 --- /dev/null +++ b/shalrath.hc @@ -0,0 +1,243 @@ +/* + * $Header: /HexenWorld/Siege/Shalrath.hc 3 5/25/98 1:39p Mgummelt $ + */ +/* +============================================================================== + +SHAL-RATH + +============================================================================== +*/ +$cd id1/models/shalrath +$origin 0 0 24 +$base base +$skin skin +$scale 0.7 + +$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8 +$frame attack9 attack10 attack11 + +$frame pain1 pain2 pain3 pain4 pain5 + +$frame death1 death2 death3 death4 death5 death6 death7 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +void() shalrath_pain; +void() ShalMissile; +void() shal_stand =[ $walk1, shal_stand ] {ai_stand();}; + +void() shal_walk1 =[ $walk2, shal_walk2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "shalrath/idle.wav", 1, ATTN_IDLE); +ai_walk(6);}; +void() shal_walk2 =[ $walk3, shal_walk3 ] {ai_walk(4);}; +void() shal_walk3 =[ $walk4, shal_walk4 ] {ai_walk(0);}; +void() shal_walk4 =[ $walk5, shal_walk5 ] {ai_walk(0);}; +void() shal_walk5 =[ $walk6, shal_walk6 ] {ai_walk(0);}; +void() shal_walk6 =[ $walk7, shal_walk7 ] {ai_walk(0);}; +void() shal_walk7 =[ $walk8, shal_walk8 ] {ai_walk(5);}; +void() shal_walk8 =[ $walk9, shal_walk9 ] {ai_walk(6);}; +void() shal_walk9 =[ $walk10, shal_walk10 ] {ai_walk(5);}; +void() shal_walk10 =[ $walk11, shal_walk11 ] {ai_walk(0);}; +void() shal_walk11 =[ $walk12, shal_walk12 ] {ai_walk(4);}; +void() shal_walk12 =[ $walk1, shal_walk1 ] {ai_walk(5);}; + +void() shal_run1 =[ $walk2, shal_run2 ] { +if (random() < 0.2) + sound (self, CHAN_VOICE, "shalrath/idle.wav", 1, ATTN_IDLE); +ai_run(6);}; +void() shal_run2 =[ $walk3, shal_run3 ] {ai_run(4);}; +void() shal_run3 =[ $walk4, shal_run4 ] {ai_run(0);}; +void() shal_run4 =[ $walk5, shal_run5 ] {ai_run(0);}; +void() shal_run5 =[ $walk6, shal_run6 ] {ai_run(0);}; +void() shal_run6 =[ $walk7, shal_run7 ] {ai_run(0);}; +void() shal_run7 =[ $walk8, shal_run8 ] {ai_run(5);}; +void() shal_run8 =[ $walk9, shal_run9 ] {ai_run(6);}; +void() shal_run9 =[ $walk10, shal_run10 ] {ai_run(5);}; +void() shal_run10 =[ $walk11, shal_run11 ] {ai_run(0);}; +void() shal_run11 =[ $walk12, shal_run12 ] {ai_run(4);}; +void() shal_run12 =[ $walk1, shal_run1 ] {ai_run(5);}; + +void() shal_attack1 =[ $attack1, shal_attack2 ] { +sound (self, CHAN_VOICE, "shalrath/attack.wav", 1, ATTN_NORM); +ai_face(); +}; +void() shal_attack2 =[ $attack2, shal_attack3 ] {ai_face();}; +void() shal_attack3 =[ $attack3, shal_attack4 ] {ai_face();}; +void() shal_attack4 =[ $attack4, shal_attack5 ] {ai_face();}; +void() shal_attack5 =[ $attack5, shal_attack6 ] {ai_face();}; +void() shal_attack6 =[ $attack6, shal_attack7 ] {ai_face();}; +void() shal_attack7 =[ $attack7, shal_attack8 ] {ai_face();}; +void() shal_attack8 =[ $attack8, shal_attack9 ] {ai_face();}; +void() shal_attack9 =[ $attack9, shal_attack10 ] {ShalMissile();}; +void() shal_attack10 =[ $attack10, shal_attack11 ] {ai_face();}; +void() shal_attack11 =[ $attack11, shal_run1 ] {}; + +void() shal_pain1 =[ $pain1, shal_pain2 ] {}; +void() shal_pain2 =[ $pain2, shal_pain3 ] {}; +void() shal_pain3 =[ $pain3, shal_pain4 ] {}; +void() shal_pain4 =[ $pain4, shal_pain5 ] {}; +void() shal_pain5 =[ $pain5, shal_run1 ] {}; + +void() shal_death1 =[ $death1, shal_death2 ] {}; +void() shal_death2 =[ $death2, shal_death3 ] {}; +void() shal_death3 =[ $death3, shal_death4 ] {}; +void() shal_death4 =[ $death4, shal_death5 ] {}; +void() shal_death5 =[ $death5, shal_death6 ] {}; +void() shal_death6 =[ $death6, shal_death7 ] {}; +void() shal_death7 =[ $death7, shal_death7 ] {}; + + +void() shalrath_pain = +{ + if (self.pain_finished > time) + return; + + sound (self, CHAN_VOICE, "shalrath/pain.wav", 1, ATTN_NORM); + shal_pain1(); + self.pain_finished = time + 3; +}; + +void() shalrath_die = +{ +// check for gib + if (self.health < -90) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("progs/h_shal.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib2.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + return; + } + + sound (self, CHAN_VOICE, "shalrath/death.wav", 1, ATTN_NORM); + shal_death1(); + self.solid = SOLID_NOT; + // insert death sounds here +}; + +/* +================ +ShalMissile +================ +*/ +void() ShalMissileTouch; +void() ShalHome; +void() ShalMissile = +{ + local entity missile; + local vector dir; + local float dist, flytime; + + dir = normalize((self.enemy.origin + '0 0 10') - self.origin); + dist = vlen (self.enemy.origin - self.origin); + flytime = dist * 0.002; + if (flytime < 0.1) + flytime = 0.1; + + self.effects = self.effects | EF_MUZZLEFLASH; + sound (self, CHAN_WEAPON, "shalrath/attack2.wav", 1, ATTN_NORM); + + missile = spawn (); + missile.owner = self; + + missile.solid = SOLID_BBOX; + missile.movetype = MOVETYPE_FLYMISSILE; + setmodel (missile, "progs/v_spike.mdl"); + + setsize (missile, '0 0 0', '0 0 0'); + + missile.origin = self.origin + '0 0 10'; + missile.velocity = dir * 400; + missile.avelocity = '300 300 300'; + missile.nextthink = flytime + time; + missile.think = ShalHome; + missile.enemy = self.enemy; + missile.touch = ShalMissileTouch; +}; + +void() ShalHome = +{ + local vector dir, vtemp; + vtemp = self.enemy.origin + '0 0 10'; + if (self.enemy.health < 1) + { + remove(self); + return; + } + dir = normalize(vtemp - self.origin); + if (skill == 3) + self.velocity = dir * 350; + else + self.velocity = dir * 250; + self.nextthink = time + 0.2; + self.think = ShalHome; +}; + +void() ShalMissileTouch = +{ + if (other == self.owner) + return; // don't explode on owner + + if (other.classname == "monster_zombie") + T_Damage (other, self, self, 110); + T_RadiusDamage (self, self.owner, 40, world); + sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_EXPLOSION); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + + self.velocity = '0 0 0'; + self.touch = SUB_Null; + setmodel (self, "progs/s_explod.spr"); + self.solid = SOLID_NOT; + s_explode1 (); +}; + +//================================================================= + +/*QUAK-ED monster_shalrath (1 0 0) (-32 -32 -24) (32 32 48) Ambush +*/ +void() monster_shalrath = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model2 ("progs/shalrath.mdl"); + precache_model2 ("progs/h_shal.mdl"); + precache_model2 ("progs/v_spike.mdl"); + + precache_sound2 ("shalrath/attack.wav"); + precache_sound2 ("shalrath/attack2.wav"); + precache_sound2 ("shalrath/death.wav"); + precache_sound2 ("shalrath/idle.wav"); + precache_sound2 ("shalrath/pain.wav"); + precache_sound2 ("shalrath/sight.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/shalrath.mdl"); + setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); + self.health = 400; + + self.th_stand = shal_stand; + self.th_walk = shal_walk1; + self.th_run = shal_run1; + self.th_die = shalrath_die; + self.th_pain = shalrath_pain; + self.th_missile = shal_attack1; + + self.think = walkmonster_start; + self.nextthink = time + 0.1 + random ()*0.1; + +}; + diff --git a/shambler.hc b/shambler.hc new file mode 100644 index 0000000..9b2d4af --- /dev/null +++ b/shambler.hc @@ -0,0 +1,371 @@ +/* + * $Header: /HexenWorld/Siege/Shambler.hc 3 5/25/98 1:39p Mgummelt $ + */ +/* +============================================================================== + +SHAMBLER + +============================================================================== +*/ + +$cd id1/models/shams +$origin 0 0 24 +$base base +$skin base + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 stand14 stand15 stand16 stand17 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 +$frame walk8 walk9 walk10 walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 + +$frame smash1 smash2 smash3 smash4 smash5 smash6 smash7 +$frame smash8 smash9 smash10 smash11 smash12 + +$frame swingr1 swingr2 swingr3 swingr4 swingr5 +$frame swingr6 swingr7 swingr8 swingr9 + +$frame swingl1 swingl2 swingl3 swingl4 swingl5 +$frame swingl6 swingl7 swingl8 swingl9 + +$frame magic1 magic2 magic3 magic4 magic5 +$frame magic6 magic7 magic8 magic9 magic10 magic11 magic12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame death1 death2 death3 death4 death5 death6 +$frame death7 death8 death9 death10 death11 + +void() sham_stand1 =[ $stand1, sham_stand2 ] {ai_stand();}; +void() sham_stand2 =[ $stand2, sham_stand3 ] {ai_stand();}; +void() sham_stand3 =[ $stand3, sham_stand4 ] {ai_stand();}; +void() sham_stand4 =[ $stand4, sham_stand5 ] {ai_stand();}; +void() sham_stand5 =[ $stand5, sham_stand6 ] {ai_stand();}; +void() sham_stand6 =[ $stand6, sham_stand7 ] {ai_stand();}; +void() sham_stand7 =[ $stand7, sham_stand8 ] {ai_stand();}; +void() sham_stand8 =[ $stand8, sham_stand9 ] {ai_stand();}; +void() sham_stand9 =[ $stand9, sham_stand10] {ai_stand();}; +void() sham_stand10 =[ $stand10, sham_stand11] {ai_stand();}; +void() sham_stand11 =[ $stand11, sham_stand12] {ai_stand();}; +void() sham_stand12 =[ $stand12, sham_stand13] {ai_stand();}; +void() sham_stand13 =[ $stand13, sham_stand14] {ai_stand();}; +void() sham_stand14 =[ $stand14, sham_stand15] {ai_stand();}; +void() sham_stand15 =[ $stand15, sham_stand16] {ai_stand();}; +void() sham_stand16 =[ $stand16, sham_stand17] {ai_stand();}; +void() sham_stand17 =[ $stand17, sham_stand1 ] {ai_stand();}; + +void() sham_walk1 =[ $walk1, sham_walk2 ] {ai_walk(10);}; +void() sham_walk2 =[ $walk2, sham_walk3 ] {ai_walk(9);}; +void() sham_walk3 =[ $walk3, sham_walk4 ] {ai_walk(9);}; +void() sham_walk4 =[ $walk4, sham_walk5 ] {ai_walk(5);}; +void() sham_walk5 =[ $walk5, sham_walk6 ] {ai_walk(6);}; +void() sham_walk6 =[ $walk6, sham_walk7 ] {ai_walk(12);}; +void() sham_walk7 =[ $walk7, sham_walk8 ] {ai_walk(8);}; +void() sham_walk8 =[ $walk8, sham_walk9 ] {ai_walk(3);}; +void() sham_walk9 =[ $walk9, sham_walk10] {ai_walk(13);}; +void() sham_walk10 =[ $walk10, sham_walk11] {ai_walk(9);}; +void() sham_walk11 =[ $walk11, sham_walk12] {ai_walk(7);}; +void() sham_walk12 =[ $walk12, sham_walk1 ] {ai_walk(7); +if (random() > 0.8) + sound (self, CHAN_VOICE, "shambler/sidle.wav", 1, ATTN_IDLE);}; + +void() sham_run1 =[ $run1, sham_run2 ] {ai_run(20);}; +void() sham_run2 =[ $run2, sham_run3 ] {ai_run(24);}; +void() sham_run3 =[ $run3, sham_run4 ] {ai_run(20);}; +void() sham_run4 =[ $run4, sham_run5 ] {ai_run(20);}; +void() sham_run5 =[ $run5, sham_run6 ] {ai_run(24);}; +void() sham_run6 =[ $run6, sham_run1 ] {ai_run(20); +if (random() > 0.8) + sound (self, CHAN_VOICE, "shambler/sidle.wav", 1, ATTN_IDLE); +}; + +void() sham_smash1 =[ $smash1, sham_smash2 ] { +sound (self, CHAN_VOICE, "shambler/melee1.wav", 1, ATTN_NORM); +ai_charge(2);}; +void() sham_smash2 =[ $smash2, sham_smash3 ] {ai_charge(6);}; +void() sham_smash3 =[ $smash3, sham_smash4 ] {ai_charge(6);}; +void() sham_smash4 =[ $smash4, sham_smash5 ] {ai_charge(5);}; +void() sham_smash5 =[ $smash5, sham_smash6 ] {ai_charge(4);}; +void() sham_smash6 =[ $smash6, sham_smash7 ] {ai_charge(1);}; +void() sham_smash7 =[ $smash7, sham_smash8 ] {ai_charge(0);}; +void() sham_smash8 =[ $smash8, sham_smash9 ] {ai_charge(0);}; +void() sham_smash9 =[ $smash9, sham_smash10 ] {ai_charge(0);}; +void() sham_smash10 =[ $smash10, sham_smash11 ] { +local vector delta; +local float ldmg; + + if (!self.enemy) + return; + ai_charge(0); + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 100) + return; + if (!CanDamage (self.enemy, self)) + return; + + ldmg = (random() + random() + random()) * 40; + T_Damage (self.enemy, self, self, ldmg); + sound (self, CHAN_VOICE, "shambler/smack.wav", 1, ATTN_NORM); + + SpawnMeatSpray (self.origin + v_forward*16, crandom() * 100 * v_right); + SpawnMeatSpray (self.origin + v_forward*16, crandom() * 100 * v_right); +}; +void() sham_smash11 =[ $smash11, sham_smash12 ] {ai_charge(5);}; +void() sham_smash12 =[ $smash12, sham_run1 ] {ai_charge(4);}; + +void() sham_swingr1; + +void(float side) ShamClaw = +{ +local vector delta; +local float ldmg; + + if (!self.enemy) + return; + ai_charge(10); + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 100) + return; + + ldmg = (random() + random() + random()) * 20; + T_Damage (self.enemy, self, self, ldmg); + sound (self, CHAN_VOICE, "shambler/smack.wav", 1, ATTN_NORM); + + if (side) + { + makevectors (self.angles); + SpawnMeatSpray (self.origin + v_forward*16, side * v_right); + } +}; + +void() sham_swingl1 =[ $swingl1, sham_swingl2 ] { +sound (self, CHAN_VOICE, "shambler/melee2.wav", 1, ATTN_NORM); +ai_charge(5);}; +void() sham_swingl2 =[ $swingl2, sham_swingl3 ] {ai_charge(3);}; +void() sham_swingl3 =[ $swingl3, sham_swingl4 ] {ai_charge(7);}; +void() sham_swingl4 =[ $swingl4, sham_swingl5 ] {ai_charge(3);}; +void() sham_swingl5 =[ $swingl5, sham_swingl6 ] {ai_charge(7);}; +void() sham_swingl6 =[ $swingl6, sham_swingl7 ] {ai_charge(9);}; +void() sham_swingl7 =[ $swingl7, sham_swingl8 ] {ai_charge(5); ShamClaw(250);}; +void() sham_swingl8 =[ $swingl8, sham_swingl9 ] {ai_charge(4);}; +void() sham_swingl9 =[ $swingl9, sham_run1 ] { +ai_charge(8); +if (random()<0.5) + self.think = sham_swingr1; +}; + +void() sham_swingr1 =[ $swingr1, sham_swingr2 ] { +sound (self, CHAN_VOICE, "shambler/melee1.wav", 1, ATTN_NORM); +ai_charge(1);}; +void() sham_swingr2 =[ $swingr2, sham_swingr3 ] {ai_charge(8);}; +void() sham_swingr3 =[ $swingr3, sham_swingr4 ] {ai_charge(14);}; +void() sham_swingr4 =[ $swingr4, sham_swingr5 ] {ai_charge(7);}; +void() sham_swingr5 =[ $swingr5, sham_swingr6 ] {ai_charge(3);}; +void() sham_swingr6 =[ $swingr6, sham_swingr7 ] {ai_charge(6);}; +void() sham_swingr7 =[ $swingr7, sham_swingr8 ] {ai_charge(6); ShamClaw(-250);}; +void() sham_swingr8 =[ $swingr8, sham_swingr9 ] {ai_charge(3);}; +void() sham_swingr9 =[ $swingr9, sham_run1 ] {ai_charge(1); +ai_charge(10); +if (random()<0.5) + self.think = sham_swingl1; +}; + +void() sham_melee = +{ + local float chance; + + chance = random(); + if (chance > 0.6 || self.health == 600) + sham_smash1 (); + else if (chance > 0.3) + sham_swingr1 (); + else + sham_swingl1 (); +}; + + +//============================================================================ + +void() CastLightning = +{ + local vector org, dir; + + self.effects = self.effects | EF_MUZZLEFLASH; + + ai_face (); + + org = self.origin + '0 0 40'; + + dir = self.enemy.origin + '0 0 16' - org; + dir = normalize (dir); + + traceline (org, self.origin + dir*600, TRUE, self); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LIGHTNING1); + WriteEntity (MSG_BROADCAST, self); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + WriteCoord (MSG_BROADCAST, trace_endpos_x); + WriteCoord (MSG_BROADCAST, trace_endpos_y); + WriteCoord (MSG_BROADCAST, trace_endpos_z); + + LightningDamage (org, trace_endpos, self, 10); +}; + +void() sham_magic1 =[ $magic1, sham_magic2 ] {ai_face(); + sound (self, CHAN_WEAPON, "shambler/sattck1.wav", 1, ATTN_NORM); +}; +void() sham_magic2 =[ $magic2, sham_magic3 ] {ai_face();}; +void() sham_magic3 =[ $magic3, sham_magic4 ] {ai_face();self.nextthink = self.nextthink + 0.2; +local entity o; + +self.effects = self.effects | EF_MUZZLEFLASH; +ai_face(); +self.owner = spawn(); +o = self.owner; +setmodel (o, "progs/s_light.mdl"); +setorigin (o, self.origin); +o.angles = self.angles; +o.nextthink = time + 0.7; +o.think = SUB_Remove; +}; +void() sham_magic4 =[ $magic4, sham_magic5 ] +{ +self.effects = self.effects | EF_MUZZLEFLASH; +self.owner.frame = 1; +}; +void() sham_magic5 =[ $magic5, sham_magic6 ] +{ +self.effects = self.effects | EF_MUZZLEFLASH; +self.owner.frame = 2; +}; +void() sham_magic6 =[ $magic6, sham_magic9 ] +{ +remove (self.owner); +CastLightning(); +sound (self, CHAN_WEAPON, "shambler/sboom.wav", 1, ATTN_NORM); +}; +void() sham_magic9 =[ $magic9, sham_magic10 ] +{CastLightning();}; +void() sham_magic10 =[ $magic10, sham_magic11 ] +{CastLightning();}; +void() sham_magic11 =[ $magic11, sham_magic12 ] +{ +if (skill == 3) + CastLightning(); +}; +void() sham_magic12 =[ $magic12, sham_run1 ] {}; + + + +void() sham_pain1 =[ $pain1, sham_pain2 ] {}; +void() sham_pain2 =[ $pain2, sham_pain3 ] {}; +void() sham_pain3 =[ $pain3, sham_pain4 ] {}; +void() sham_pain4 =[ $pain4, sham_pain5 ] {}; +void() sham_pain5 =[ $pain5, sham_pain6 ] {}; +void() sham_pain6 =[ $pain6, sham_run1 ] {}; + +void(entity attacker, float damage) sham_pain = +{ + sound (self, CHAN_VOICE, "shambler/shurt2.wav", 1, ATTN_NORM); + + if (self.health <= 0) + return; // allready dying, don't go into pain frame + + if (random()*400 > damage) + return; // didn't flinch + + if (self.pain_finished > time) + return; + self.pain_finished = time + 2; + + sham_pain1 (); +}; + + +//============================================================================ + +void() sham_death1 =[ $death1, sham_death2 ] {}; +void() sham_death2 =[ $death2, sham_death3 ] {}; +void() sham_death3 =[ $death3, sham_death4 ] {self.solid = SOLID_NOT;}; +void() sham_death4 =[ $death4, sham_death5 ] {}; +void() sham_death5 =[ $death5, sham_death6 ] {}; +void() sham_death6 =[ $death6, sham_death7 ] {}; +void() sham_death7 =[ $death7, sham_death8 ] {}; +void() sham_death8 =[ $death8, sham_death9 ] {}; +void() sham_death9 =[ $death9, sham_death10 ] {}; +void() sham_death10 =[ $death10, sham_death11 ] {}; +void() sham_death11 =[ $death11, sham_death11 ] {}; + +void() sham_die = +{ +// check for gib + if (self.health < -60) + { + sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM); + ThrowHead ("progs/h_shams.mdl", self.health); + ThrowGib ("progs/gib1.mdl", self.health); + ThrowGib ("progs/gib2.mdl", self.health); + ThrowGib ("progs/gib3.mdl", self.health); + return; + } + +// regular death + sound (self, CHAN_VOICE, "shambler/sdeath.wav", 1, ATTN_NORM); + sham_death1 (); +}; + +//============================================================================ + + +/*QUAK-ED monster_shambler (1 0 0) (-32 -32 -24) (32 32 64) Ambush +*/ +void() monster_shambler = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/shambler.mdl"); + precache_model ("progs/s_light.mdl"); + precache_model ("progs/h_shams.mdl"); + precache_model ("progs/bolt.mdl"); + + precache_sound ("shambler/sattck1.wav"); + precache_sound ("shambler/sboom.wav"); + precache_sound ("shambler/sdeath.wav"); + precache_sound ("shambler/shurt2.wav"); + precache_sound ("shambler/sidle.wav"); + precache_sound ("shambler/ssight.wav"); + precache_sound ("shambler/melee1.wav"); + precache_sound ("shambler/melee2.wav"); + precache_sound ("shambler/smack.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + setmodel (self, "progs/shambler.mdl"); + + setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); + self.health = 600; + + self.th_stand = sham_stand1; + self.th_walk = sham_walk1; + self.th_run = sham_run1; + self.th_die = sham_die; + self.th_melee = sham_melee; + self.th_missile = sham_magic1; + self.th_pain = sham_pain; + + walkmonster_start(); +}; + diff --git a/shardice.hc b/shardice.hc new file mode 100644 index 0000000..fe0b1eb --- /dev/null +++ b/shardice.hc @@ -0,0 +1,107 @@ +/* + * $Header: /HexenWorld/Siege/shardice.hc 5 5/25/98 10:56p Mgummelt $ + */ +/* +============================================================================== + +ice shard (IMP) + +============================================================================== +*/ + +// For building the model +$cd q:/art/models/monsters/imp/final +$base shrdbase 64 128 +$skin shrdskin + +$frame shard + + +void() shardTouch = +{ +float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + if(self.owner.classname=="monster_imp_lord") + damg = random(33,77); + else + damg = random(5,10); + + if(other.health<=damg&&other.thingtype==THINGTYPE_FLESH&&random()<0.1) + SnowJob(other,self); + else if (other.health) + { + T_Damage (other, self, self.owner, damg ); + sound (self, CHAN_BODY, "crusader/icehit.wav", 1, ATTN_NORM); + if(other.classname=="player") + { + other.artifact_active(+)ARTFLAG_FROZEN; + newmis=spawn(); + newmis.enemy=other; + newmis.artifact_active=ARTFLAG_FROZEN; + newmis.think=remove_artflag; + thinktime newmis : 0.1; + } + } + remove(self); +}; + + + + + +//============================================================================ + + +void() shard_1 =[ $shard , shard_1 ] { }; + + +//============================================================================ + + +void(vector offset, float set_speed, vector dest_offset) do_shard = +{ +entity missile; +vector vec; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.health = 10; + + if(self.classname=="monster_imp_lord") + { + set_speed*=2; + missile.scale=2; + } + + setmodel (missile, "models/shardice.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + +// set missile speed + + makevectors (self.angles); + vec = self.origin + self.view_ofs + v_factor(offset); + setorigin (missile, vec); + + vec = self.enemy.origin - missile.origin + self.enemy.proj_ofs + dest_offset; + vec = normalize(vec); + + missile.velocity = (vec+aim_adjust(self.enemy))*set_speed; + missile.angles = vectoangles(missile.velocity); + + missile.touch = shardTouch; + + missile.think = shard_1; + missile.nextthink = time + HX_FRAME_TIME; +}; + diff --git a/sheep.hc b/sheep.hc new file mode 100644 index 0000000..af9ce1e --- /dev/null +++ b/sheep.hc @@ -0,0 +1,1013 @@ +/* + * $Header: /HexenWorld/Siege/sheep.hc 16 6/01/98 2:49a Mgummelt $ + */ + +/* +============================================================================== + +Q:\art\models\players\SHEEP\ambient\sheep.hc +MG +============================================================================== +*/ + +// For building the model +$cd Q:\art\models\players\SHEEP\ambient +$origin 20 0 11 +$base BASE SKIN +$skin SKIN +$flags 0 + +// +$frame grazeA1 grazeA2 grazeA3 grazeA4 grazeA5 +$frame grazeA6 grazeA7 grazeA8 grazeA9 grazeA10 +$frame grazeA11 grazeA12 grazeA13 grazeA14 grazeA15 +$frame grazeA16 grazeA17 grazeA18 grazeA19 grazeA20 +$frame grazeA21 grazeA22 grazeA23 grazeA24 grazeA25 +$frame grazeA26 grazeA27 grazeA28 grazeA29 grazeA30 +$frame grazeA31 grazeA32 grazeA33 grazeA34 grazeA35 +$frame grazeA36 grazeA37 grazeA38 grazeA39 grazeA40 + +// +$frame grazeB1 grazeB2 grazeB3 grazeB4 grazeB5 +$frame grazeB6 grazeB7 grazeB8 grazeB9 grazeB10 +$frame grazeB11 grazeB12 grazeB13 grazeB14 grazeB15 +$frame grazeB16 grazeB17 grazeB18 grazeB19 grazeB20 +$frame grazeB21 grazeB22 grazeB23 grazeB24 grazeB25 +$frame grazeB26 grazeB27 grazeB28 grazeB29 grazeB30 +$frame grazeB31 grazeB32 grazeB33 grazeB34 grazeB35 +$frame grazeB36 grazeB37 grazeB38 grazeB39 grazeB40 + +// +$frame gstepA10 gstepA11 gstepA12 gstepA13 gstepA14 +$frame gstepA15 gstepA16 gstepA17 gstepA18 gstepA19 +$frame gstepA20 gstepA21 gstepA22 gstepA23 gstepA24 +$frame gstepA25 gstepA26 gstepA27 gstepA28 gstepA29 +$frame gstepA30 + +// +$frame gstepB10 gstepB11 gstepB12 gstepB13 gstepB14 +$frame gstepB15 gstepB16 gstepB17 gstepB18 gstepB19 +$frame gstepB20 gstepB21 gstepB22 gstepB23 gstepB24 +$frame gstepB25 gstepB26 gstepB27 gstepB28 gstepB29 +$frame gstepB30 + +// +$frame lookup1 lookup2 lookup3 lookup4 lookup5 +$frame lookup6 lookup7 lookup8 lookup9 lookup10 +$frame lookup11 lookup12 look1 look2 look3 +$frame look4 look5 look6 look7 look8 +$frame look9 look10 look11 look12 look13 +$frame look14 look15 look16 look17 look18 +$frame look19 look20 look21 look22 look23 +$frame look24 look25 look26 look27 look28 +$frame look29 look30 look31 look32 look33 +$frame look34 look35 look36 look37 look38 +$frame look39 look40 look41 look42 look43 +$frame look44 look45 look46 look47 look48 +$frame look49 look50 look51 look52 look53 +$frame look54 look55 look56 look57 look58 +$frame look59 look60 + +// +$frame pain1 pain2 pain3 pain4 pain5 +$frame pain6 pain7 pain8 + +// +$frame tranA1 tranA2 tranA3 tranA4 tranA5 +$frame tranA6 tranA7 tranA8 tranA9 tranA10 + +// +$frame tranB1 tranB2 tranB3 tranB4 tranB5 +$frame tranB6 tranB7 tranB8 tranB9 tranB10 +$frame tranB11 tranB12 + +// +$frame trot1 trot2 trot3 trot4 trot5 +$frame trot6 trot7 trot8 trot9 trot10 + +// +$frame wait1 wait2 wait3 wait4 wait5 +$frame wait6 wait7 wait8 wait9 wait10 +$frame wait11 wait12 wait13 wait14 wait15 +$frame wait16 + +float stationary = 1; + +/*QUAKED player_sheep (0.3 0.1 0.6) (-8 -8 -0) (8 8 32) stationary STUCK JUMP x DORMANT NODROP start_frozen respawn +A sheep player model +-------------------------FIELDS------------------------- +stationary- sheep will not wander around or change angles +nodrop- won't drop to floor (and through other entities!) on spawn +-------------------------------------------------------- +*/ +void()sheep_tranA; +void()sheep_tranB; +void()sheep_graze_a; +void()sheep_graze_b; +void()sheep_gstep_a; +void()sheep_gstep_b; +void()sheep_trot; +void()sheep_wait; +void()sheep_pain; +void()sheep_lookdown; +void()sheep_look; +void()sheep_lookup; + +/* +void restore_monster () +{ +//SOUND and MODEL + newmis=spawn(); + thinktime newmis : 0; + newmis.think=self.th_init; + newmis.skin=self.skin; + newmis.health=self.max_health; + remove(self); +} +*/ + +void sheep_sound (float vol) +{ +float r; +string playsound; + if(self.noise!=""&&self.classname!="player") + playsound=self.noise; + else + { + r=rint(random(1,3)); + if(r==1) + playsound="misc/sheep1.wav"; + else if(r==2) + playsound="misc/sheep2.wav"; + else + playsound="misc/sheep3.wav"; + } + sound(self,CHAN_VOICE,playsound,vol,ATTN_NORM); + self.pain_finished=time + 1; +} + +void sheep_turn (void) +{ + if(random()<0.5) + self.angles_y+=random()*self.yaw_speed+self.yaw_speed/2; + else + self.angles_y-=random()*self.yaw_speed+self.yaw_speed/2; + +} + +void sheep_move (float dist) +{ +vector best_yaw; + best_yaw=normalize(self.goalentity.origin-self.origin); + best_yaw=vectoangles(best_yaw); + self.ideal_yaw=best_yaw_y; + ChangeYaw(); + movetogoal(dist); +} + +void sheep_think (void) +{ + MonsterCheckContents(); + if(!self.spawnflags&stationary&&(self.think==sheep_trot||self.think==sheep_gstep_a||self.think==sheep_gstep_b)&&random()<0.1) + sheep_turn(); + + if(random()<0.1&&random()<0.2&&self.pain_finished25) + self.health=25; + } + + CreateEntityNew(self,ENT_SHEEP,"models/sheep.mdl",sheep_die); + + if(world.target=="sheep"||dmMode==DM_SIEGE) + { + self.use=sheep_run_use; + self.scale=random(0.05,2.55); + self.experience_value=rint(3.5*self.scale); + self.init_org=self.origin; + self.th_init=player_sheep; + self.health+=10*self.scale; + self.mins=self.mins*self.scale; + self.maxs=self.maxs*self.scale; + + if(self.mins_x>-5) + self.mins_x=-5; + if(self.mins_y>-5) + self.mins_y=-5; + if(self.mins_z>-5) + self.mins_z=-5; + + if(self.maxs_x<5) + self.maxs_x=5; + if(self.maxs_y<5) + self.maxs_y=5; + if(self.maxs_z<5) + self.maxs_z=5; + + setsize(self,self.mins,self.maxs); + } + self.th_pain = sheep_pain; + self.touch = obj_push; + self.flags(+)FL_PUSH; + self.flags2(+)FL_ALIVE; + self.yaw_speed=2; + self.speed=3; + self.th_run=sheep_wait; + + if(self.scale) + self.drawflags(+)SCALE_ORIGIN_BOTTOM; +// if(self.spawnflags&SHEEP_RESPAWN) + self.wallspot=self.origin; + +//FIXME: Don't allow trans, trot, etc, if stationary flag on + self.think=SUB_Null; + r=rint(random(1,3)); + if(r==1) + self.noise="misc/sheep1.wav"; + else if(r==2) + self.noise="misc/sheep2.wav"; + else + self.noise="misc/sheep3.wav"; + + if(self.enemy) + self.think=self.th_run=monster_sheep_run; + else + { + r=rint(random(1,11)); + if(r==1) + self.think=sheep_graze_a; + else if(r==2) + self.think=sheep_graze_b; + else if(r==3&&!self.spawnflags&1) + self.think=sheep_gstep_a; + else if(r==4&&!self.spawnflags&1) + self.think=sheep_gstep_b; + else if(r==5) + self.think=sheep_look; + else if(r==6) + self.think=sheep_lookup; + else if(r==7&&!self.spawnflags&1) + self.think=sheep_trot; + else if(r==8) + self.think=sheep_wait; + else if(r==9) + self.think=sheep_lookdown; + else if(r==10&&!self.spawnflags&1) + self.think=sheep_tranA; + else if(!self.spawnflags&1) + self.think=sheep_tranB; + else + self.think=sheep_wait; + } + + if(self.think==SUB_Null) + self.think=sheep_wait; + + self.th_walk=self.th_stand=self.think; +//These next few are super-paranoid, but the fucking sheep just + //keep fucking crashing!!!! + if(!self.th_walk) + self.th_walk=sheep_wait; + if(!self.th_stand) + self.th_stand=sheep_wait; + if(self.th_walk==SUB_Null) + self.th_walk=sheep_wait; + if(self.th_stand==SUB_Null) + self.th_stand=sheep_wait; + + self.takedamage=DAMAGE_YES; + self.flags2(+)FL_ALIVE; + + if(self.scale<=0) + self.scale=1; + + if(!self.touch) + self.touch=obj_push; + + self.origin_z = self.origin_z + 1; // raise off floor a bit + droptofloor(); + if (!walkmove(0,0, FALSE)) + { + if(self.flags2&FL_SUMMONED) + remove(self); + else + { + dprint ("walkmonster in wall at: "); + dprint (vtos(self.origin)); + dprint ("\n"); + } + } + + self.ideal_yaw = self.angles * '0 1 0'; + + if (!self.yaw_speed) + self.yaw_speed = 20; + + if(self.view_ofs=='0 0 0') + self.view_ofs = '0 0 25'; + + if(self.proj_ofs=='0 0 0') + self.proj_ofs = '0 0 25'; + + if(!self.use) + self.use = monster_use; + + self.flags(-)FL_MONSTER; + + self.pausetime = 99999999; + + spawn_push_trigger(3); + + self.th_stand (); +} +/* +void spawn_sheep (vector org) +{ +entity newsheep; + newsheep=spawn(); + newsheep.classname="player_sheep"; + newsheep.spawnflags=self.spawnflags; + newsheep.think=player_sheep; + thinktime newsheep : 0.5; +} +*/ +/* +============================ +PLAYER SHEEP +============================ +*/ +void()player_sheep_run; + +void player_sheep_snout_slowpuff () +{ + self.wfs = advanceweaponframe(22,31); + self.th_weapon=player_sheep_snout_slowpuff; +} + +void player_sheep_snout_fastpuff () +{ + self.wfs = advanceweaponframe(17,21); + self.th_weapon=player_sheep_snout_fastpuff; + if(self.wfs==WF_CYCLE_WRAPPED) + self.weaponframe_cnt+=1; + if(self.weaponframe_cnt>5) + { + self.weaponframe_cnt=0; + player_sheep_snout_slowpuff(); + } +} + +void player_sheep_snout_bite () +{ + self.wfs = advanceweaponframe(8,16); + self.th_weapon=player_sheep_snout_bite; + if(self.wfs==WF_CYCLE_WRAPPED) + player_sheep_snout_fastpuff(); +} + +void player_sheep_snout_pain1 () +{ + self.wfs = advanceweaponframe(0,3); + self.th_weapon=player_sheep_snout_pain1; + if(self.wfs==WF_CYCLE_WRAPPED) + player_sheep_snout_fastpuff(); +} + +void player_sheep_snout_pain2 () +{ + self.wfs = advanceweaponframe(4,7); + self.th_weapon=player_sheep_snout_pain2; + if(self.wfs==WF_CYCLE_WRAPPED) + player_sheep_snout_fastpuff(); +} + +void() player_sheep_stand =[++$wait1..$wait16] +{ + self.th_weapon(); + if (self.velocity_x || self.velocity_y) + self.think=player_sheep_run; +}; + +void() player_sheep_run =[++$trot1..$trot10] +{ + self.th_weapon(); + if (!self.velocity_x && !self.velocity_y) + self.think=player_sheep_stand; +}; + +void player_sheep_baa () +{ + self.th_weapon=player_sheep_snout_bite; + self.th_weapon(); + traceline(self.origin+self.view_ofs,self.origin+self.view_ofs+v_forward*36,FALSE,self); + if(trace_ent.takedamage)//classname=="obj_catapult2") + { + sound(self,CHAN_VOICE,"spider/bite.wav",1,ATTN_NORM); + SpawnPuff (trace_endpos, '0 0 0', 3,trace_ent); + T_Damage(trace_ent,self,self,5); + } + else + sheep_sound(1); + + self.attack_finished=time+0.5; + + if(!self.velocity_x && !self.velocity_y) + self.think=player_sheep_stand; + else + self.think=player_sheep_run; + thinktime self : 0; +} + +void() player_sheep_pain=[++$pain1..$pain8] +{ + if(self.pain_finished25) + loser.health=25; + loser.th_missile=player_sheep_baa; + loser.th_melee=player_sheep_baa; + loser.th_stand=player_sheep_stand; + loser.th_run=player_sheep_run; + loser.th_walk=player_sheep_run; + loser.th_pain=player_sheep_pain; + loser.th_jump=player_sheep_jump; + + loser.oldskin=loser.skin; + loser.skin=0; + setmodel (loser, "models/sheep.mdl"); + setsize (loser,'-16 -16 0','16 16 28'); + loser.model="models/sheep.mdl"; +// loser.modelindex=modelindex_sheep; +// loser.headmodel="models/h_sheep.mdl"; + loser.th_weapon=player_sheep_snout_pain1; + loser.hull=HULL_CROUCH; +// if(!loser.flags2&FL_CAMERA_VIEW) + loser.view_ofs = '0 0 24'; + loser.proj_ofs='0 0 18'; + loser.attack_finished=0; + loser.weapon=FALSE; + loser.weaponmodel="models/snout.mdl"; + loser.weaponframe=0; + loser.sheep_sound_time=FALSE; + + loser.think=player_sheep_stand; + thinktime loser : 0; + } + else + { + //sound(loser,CHAN_BODY,"misc/null.wav",1,ATTN_NONE); + //sound(loser,CHAN_WEAPON,"misc/null.wav",1,ATTN_NONE); + //sound(loser,CHAN_ITEM,"misc/null.wav",1,ATTN_NONE); + newmis=spawn(); + setorigin(newmis,loser.origin); + +//For restoring monster: + newmis.th_spawn=loser.th_spawn; + newmis.skin=0; + newmis.oldskin=loser.skin; + newmis.max_health=loser.health; + if(!loser.enemy) + newmis.enemy=self.owner; + else + newmis.enemy=loser.enemy; + newmis.goalentity=newmis.enemy; + newmis.angles=loser.angles; + newmis.target=loser.target;//So it will still activate targets + newmis.killtarget=loser.killtarget; + remove(loser); + newmis.flags2(+)FL_SUMMONED; + newmis.spawnflags(+)NO_DROP; + newmis.think=player_sheep; + thinktime newmis : 0; + } +} + +void PolyTurn(entity bolt) +{ + vector dir; + + bolt.xbo_startpos = bolt.origin; + dir = vectoangles(bolt.velocity); + updateeffect(bolt.xbo_effect_id, CE_HWSHEEPINATOR, bolt.boltnum*16+128, dir_x, dir_y, bolt.origin); +} + + +void poly_RemoveEffect (void) +{ + endeffect(MSG_ALL,self.xbo_effect_id); + remove(self); +} + +void poly_FinishBoltEffect (void) +{ + entity finisher; + finisher = spawn(); + finisher.think = poly_RemoveEffect; + finisher.xbo_effect_id = self.xbo_effect_id; + thinktime finisher : 1.0; +} + +void poly_RemoveBoltFromList (void) +{ + entity curbolt; + + if (self.xbo_effect_id == -1) + { + return; + } + + if ((self == self.firstbolt)&&(self.nextbolt == world))//i'm the last guy in the list--stop effect + { + poly_FinishBoltEffect(); + return; + } + + if (self == self.firstbolt)//i'm the first in the list--let everyone know that the the new head of the list is the one after me + { + curbolt = self.nextbolt; + while ((curbolt != world)&&(curbolt != curbolt.nextbolt)) + { + curbolt.firstbolt = self.nextbolt; + curbolt = curbolt.nextbolt; + } + } + else + { + curbolt = self.firstbolt; + while ((curbolt != world)&&(curbolt.nextbolt != self)) + { + curbolt = curbolt.nextbolt; + } + if(curbolt) + curbolt.nextbolt = self.nextbolt; + } +} + +void poly_HitEffect (vector v_forward) +{ + vector stickspot; + float ttype; + + stickspot = v_forward * 8; + + //build the impact code byte now: + + //lowest 4 bits of byte indicate thingtype--can't use THINGTYPE_ consts because there are too many + ttype = GetImpactType(other); + + if (other.takedamage)//high bit of the byte indicates whether hit object takes damage + { + ttype += 128; + } + + ttype += self.boltnum * 16;//2nd, 3rd, and 4th higshest bits in byte indicate bolt number + + ttype += 1;//lowest bit set means that this bolt has hit + + //done building impact code byte**** + + //now figure out how far i've travelled + + stickspot = self.origin-self.xbo_startpos; + + updateeffect(self.xbo_effect_id, CE_HWSHEEPINATOR, ttype, vlen(stickspot)); + + poly_RemoveBoltFromList(); + self.xbo_effect_id = -1; +} + +void poly_touch () +{ + vector forward; + forward = vectoangles(self.velocity); + + if(other.beast_time>time) + UnBeast(other); + + if(other.playerclass==CLASS_DWARF|| + ((other.monsterclass >= CLASS_BOSS&&other!=self.owner)||((dmMode == DM_CAPTURE_THE_TOKEN)&&(other.gameFlags & GF_HAS_TOKEN))) + ) + { // you can't sheep the token guy... + self.velocity=normalize((self.owner.absmin+self.owner.absmax)*0.5-self.origin)*700; + self.owner=other; + PolyTurn(self); + self.touch=SUB_Null; + particleexplosion(self.origin,random(144,159),self.absmax_z-self.absmin_z,10); + remove(self); + } + else if(other.flags2&FL_ALIVE&&other.model!="models/sheep.mdl"&&other.classname!="monster_golem_crystal") + { + poly_HitEffect(forward); + self.touch=SUB_Null; + Polymorph(other); + remove(self); + } + else if(other.movetype!=MOVETYPE_FLYMISSILE&&other.movetype!=MOVETYPE_BOUNCE&&other.movetype!=MOVETYPE_BOUNCEMISSILE) + { + poly_HitEffect(forward); + self.touch=SUB_Null; +// particleexplosion(self.origin,random(144,159),self.absmax_z-self.absmin_z,10); + remove(self); + } +} + +void polymorph_anim () [++ 0 .. 3] +{ + 8; +// particle4(self.origin,7,random(144,159),PARTICLETYPE_EXPLODE2,random(1,5)); +} + +entity FirePoly (float ofs, entity prevEnt, float effectNum, float boltnumber) +{ + makevectors(self.v_angle); + newmis=spawn(); + + newmis.xbo_effect_id = effectNum; + + // make sll of bolts in this effect + if (prevEnt == world) + { + newmis.firstbolt = newmis; + } + else + { + prevEnt.nextbolt = newmis; + newmis.firstbolt = prevEnt.firstbolt; + } + newmis.nextbolt = world; + + newmis.boltnum = boltnumber; + + newmis.movetype=MOVETYPE_FLYMISSILE; + newmis.solid=SOLID_BBOX; + newmis.owner=self; + newmis.touch=poly_touch; + newmis.speed=700; + newmis.velocity=v_forward*newmis.speed+v_right*ofs; + newmis.classname="polyblob"; + + newmis.drawflags=MLS_POWERMODE; + + newmis.think=polymorph_anim; + thinktime newmis : 0; +// setmodel(newmis,"models/polymrph.spr"); + setsize(newmis,'0 0 0','0 0 0'); + setorigin(newmis,self.origin+self.proj_ofs+v_forward*10); + + newmis.xbo_startpos = newmis.origin; + + return (newmis); +} + +void Use_Polymorph () +{ + float sheepviddy; + entity curBlob; + + sheepviddy = starteffect(CE_HWSHEEPINATOR, self.origin+self.proj_ofs+v_forward*10, self.v_angle); + + curBlob=FirePoly(-150,world,sheepviddy,0); + curBlob=FirePoly(-75,curBlob,sheepviddy,1); + curBlob=FirePoly(0,curBlob,sheepviddy,2); + curBlob=FirePoly(75,curBlob,sheepviddy,3); + curBlob=FirePoly(150,curBlob,sheepviddy,4); + + self.cnt_polymorph -= 1; +} diff --git a/shield.hc b/shield.hc new file mode 100644 index 0000000..9596be3 --- /dev/null +++ b/shield.hc @@ -0,0 +1,66 @@ +/* +FORCE FIELD +MG +*/ + +void() ForceFieldDie = +{ + //FIXME: add more + self.flags2-=FL_SHIELDED; + remove(self.shield); +}; + +void() ForceFieldPain = +{ + if(self.shield.pain_finished>time) + return; + sound(self.shield,CHAN_AUTO,"misc/pulse.wav",1,ATTN_NORM); + stuffcmd (self, "bf\n"); + self.shield.pain_finished=time + 1; + if(self.shield.drawflags&MLS_POWERMODE) + { + self.shield.drawflags = MLS_ABSLIGHT + DRF_TRANSLUCENT; + self.shield.abslight = 1; + } +}; + +void() ForceFieldThink= +{ + if(self.pain_finished= 6)) + { +// msg_entity=self; +// WriteByte (MSG_ONE, SVC_SET_VIEW_TINT); +// WriteByte (MSG_ONE, 168); + + chance = (self.level - 5) * .04; + if (chance > .20) + chance = .2; + + if (random() < chance) + { + point_chance = (self.level - 5) * 2; + if (point_chance > 10) + point_chance = 10; + + sound (self, CHAN_BODY, "weapons/drain.wav", 1, ATTN_NORM); + + self.health += point_chance; + if (self.health>self.max_health) + self.health = self.max_health; + } + } + + if (self.artifact_active & ART_TOMEOFPOWER) + { + damage_base = WEAPON1_PWR_BASE_DAMAGE; + damage_mod = WEAPON1_PWR_ADD_DAMAGE; + + CreateWhiteFlash(org); + + if(trace_ent.mass<=10) + inertia=1; + else + inertia=trace_ent.mass/10; + + if ((trace_ent.hull != HULL_BIG) && (inertia<1000) && (trace_ent.classname != "breakable_brush")) + { + if (trace_ent.mass < 1000) + { + dir = trace_ent.origin - self.origin; + trace_ent.velocity = dir * WEAPON1_PUSH*(1/inertia); + if(trace_ent.movetype==MOVETYPE_FLY) + { + if(trace_ent.flags&FL_ONGROUND) + trace_ent.velocity_z=200/inertia; + } + else + trace_ent.velocity_z = 200/inertia; + trace_ent.flags(-)FL_ONGROUND; + } + } + } + else + { + damage_base = WEAPON1_BASE_DAMAGE; + damage_mod = WEAPON1_ADD_DAMAGE; + } + + damg = random(damage_mod + damage_base,damage_base); + SpawnPuff (org, '0 0 0', damg,trace_ent); + T_Damage (trace_ent, self, self, damg); + + if (!MetalHitSound(trace_ent.thingtype)) + sound (self, CHAN_WEAPON, "weapons/slash.wav", 1, ATTN_NORM); + } + else + { // hit wall + sound (self, CHAN_WEAPON, "weapons/hitwall.wav", 1, ATTN_NORM); + WriteByte (MSG_MULTICAST, SVC_TEMPENTITY); + WriteByte (MSG_MULTICAST, TE_GUNSHOT); + WriteByte (MSG_MULTICAST, 1); + WriteCoord (MSG_MULTICAST, org_x); + WriteCoord (MSG_MULTICAST, org_y); + WriteCoord (MSG_MULTICAST, org_z); + multicast(self.origin,MULTICAST_PHS); + + if (self.artifact_active & ART_TOMEOFPOWER) + CreateWhiteFlash(org); + else + { + org = trace_endpos + (v_forward * -1) + (v_right * 15); + org -= '0 0 26'; + CreateSpark (org); + } + } + +} + + +void sickle_ready (void) +{ + self.th_weapon=sickle_ready; + self.weaponframe = $rootpose; +} + + +void () sickle_c = +{ + + self.th_weapon=sickle_c; + self.wfs = advanceweaponframe($3swipe1,$3swipe14); + + if (self.weaponframe==$3swipe1) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $3swipe7) + sickle_fire(); + if (self.wfs==WF_LAST_FRAME) + sickle_ready(); +}; + +void () sickle_b = +{ + self.th_weapon=sickle_b; + self.wfs = advanceweaponframe($2swipe1,$2swipe14); + + if (self.weaponframe==$2swipe1) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $2swipe3) + sickle_fire(); + else if (self.wfs == WF_LAST_FRAME) + sickle_ready(); +}; + +void () sickle_a = +{ + self.th_weapon=sickle_a; + self.wfs = advanceweaponframe($1swipe4,$1swipe17); + + if (self.weaponframe==$1swipe4) + sound (self, CHAN_WEAPON, "weapons/gaunt1.wav", 1, ATTN_NORM); + else if (self.weaponframe == $1swipe5) + sickle_fire(); + else if (self.wfs == WF_LAST_FRAME) + sickle_ready(); + +}; + +void sickle_select (void) +{ + //selection sound? + self.th_weapon=sickle_select; + self.wfs = advanceweaponframe($select10,$select1); + self.weaponmodel = "models/sickle.mdl"; + if(self.wfs==WF_CYCLE_STARTED) + sound(self,CHAN_WEAPON,"weapons/unsheath.wav",1,ATTN_NORM); + if (self.wfs==WF_CYCLE_WRAPPED) + { + self.attack_finished = time - 1; + sickle_ready(); + } +} + +void sickle_deselect (void) +{ + self.th_weapon=sickle_deselect; + self.wfs = advanceweaponframe($select1,$select10); + if (self.wfs==WF_CYCLE_WRAPPED) + W_SetCurrentAmmo(); +} + +void sickle_decide_attack (void) +{ + if (self.attack_cnt < 1) + sickle_a (); + else + { + sickle_b (); + self.attack_cnt = -1; + } + + self.attack_cnt += 1; + self.attack_finished = time + 0.5; +} + diff --git a/siege.hc b/siege.hc new file mode 100644 index 0000000..4e744fa --- /dev/null +++ b/siege.hc @@ -0,0 +1,182 @@ +/* +========================================================== + +Siege.hc + +Totally new entities specifically for Siege + +Mike Gummelt + +========================================================== +*/ + +//New effects for players +void turn_undead () {return;} + +float num_for_weap (float it_weap) +{ + if(it_weap==IT_WEAPON1) + return 1; + else if(it_weap==IT_WEAPON2) + return 2; + else if(it_weap==IT_WEAPON3) + return 3; + else if(it_weap==IT_WEAPON4) + return 4; + else if(it_weap==IT_WEAPON5) + return 5; + else if(it_weap==IT_WEAPON6) + return 6; + else if(it_weap==IT_WEAPON7) + return 7; + else if(it_weap==IT_WEAPON8) + return 8; + else + return 0; +} + +float melee_dmg_mod_for_strength (float str_value) +{ +float mod_return; + mod_return=(str_value - 10)/4; + if(mod_return<0.3) + mod_return=0.3; + return mod_return; +} + +/* +class 1 - 5 +weapons 1 - 3 +rate of fire - seconds between shots +accuracy - 0 to 1 * random vector +*/ + +float rate_and_acc_for_weap [36] = +{ + 0.3,0, 0.2,0, 2,.33, //paladin + 0.2,0, 0,0, 0,0, //crusader + 0.3,0, 2.5,.2, 0,0, //necro + 0.1,0, 1,0, 3,0, //assassin + 0.1,0, 0.3,0, 1,0.1, //succubus + 0.2,0, 0.1,0, 0,0 //dwarf +}; + +/* +class 1 - 6 +*/ + +float player_swim_mod [6] = +{ + 1, //paladin- has free action - already ok + .9, //crusader + .82, //necro + 1.2, //assassin + .75, //succubus + 1 //dwarf - fucked in C code already +}; +/* +class 1 - 6 +*/ + +float player_jump_mod [6] = +{ + 1.2,//paladin + 0.9,//crusader + 0.8,//necro + 1.5,//assassin + 2,//succubus + 0.65//dwarf +}; + +void WriteTeam (float svmsg,entity holder) +{ + entity found; + found=find(world,classname,"player"); + while(found) + { + if(found.flags&FL_CLIENT) + { + msg_entity = found; + switch(svmsg) + { + case SVC_HASKEY://send to all- in case need to clear out previous owner on any team + WriteByte(MSG_ONE,svmsg); + if(found.siege_team==other.siege_team) + WriteEntity(MSG_ONE,holder);//tell team + else + WriteEntity(MSG_ONE,world);//clear opposite team + break; + case SVC_NONEHASKEY://just send to team of last holder + if(found.siege_team==holder.siege_team) + WriteByte(MSG_ONE,svmsg); + break; + case SVC_ISDOC://only send to def. + if(found.siege_team==ST_DEFENDER) + { + WriteByte(MSG_ONE,svmsg); + WriteEntity(MSG_ONE,holder); + } + break; + case SVC_NODOC://only to def. + if(found.siege_team==ST_DEFENDER) + WriteByte(MSG_ONE,svmsg); + break; + } + } + found=find(found,classname,"player"); + } +} + +//Teleport Triggers call this +void become_defender (entity defent) +{ + if(defent.classname!="player"||defent.siege_team==ST_DEFENDER) + return; + defent.siege_team=ST_DEFENDER; + defent.skin=0; + defent.last_time=time; + defent.health=defent.max_health; + setsiegeteam(defent,ST_DEFENDER);//update C and clients + bprintname(PRINT_HIGH,defent); + bprint(PRINT_HIGH," becomes a Defender!\n"); + self.target="defender"; +} + +void become_attacker (entity attent) +{ + if(attent.classname!="player"||attent.siege_team==ST_ATTACKER) + return; + attent.siege_team=ST_ATTACKER; + attent.skin=1; + attent.last_time=time; + attent.health=attent.max_health; + setsiegeteam(attent,ST_ATTACKER);//update C and clients + bprintname(PRINT_HIGH,attent); + bprint(PRINT_HIGH," becomes an Attacker!\n"); + self.target="attacker"; +} + +void become_either (entity eitherent) +{ +entity found; +float num_att,num_def; + num_att=num_def=0; + found=find(world,classname,"player"); + while(found) + { + if(found.siege_team==ST_ATTACKER) + num_att+=1; + else if(found.siege_team==ST_DEFENDER) + num_def+=1; + found=find(found,classname,"player"); + } + if(num_att>num_def) + become_defender(eitherent); + else if(num_def>num_att) + become_attacker(eitherent); + else if(random()<0.5) + become_defender(eitherent); + else + become_attacker(eitherent); +} + diff --git a/skullwiz.hc b/skullwiz.hc new file mode 100644 index 0000000..19cb431 --- /dev/null +++ b/skullwiz.hc @@ -0,0 +1,1127 @@ +/* + * $Header: /HexenWorld/Siege/skullwiz.hc 3 5/25/98 1:39p Mgummelt $ + */ + +// +$frame skdeth1 skdeth2 skdeth3 skdeth4 skdeth5 +$frame skdeth6 skdeth7 skdeth8 skdeth9 skdeth10 +$frame skdeth11 skdeth12 skdeth13 skdeth14 skdeth15 + +// +$frame skgate1 skgate2 skgate3 skgate4 skgate5 +$frame skgate6 skgate7 skgate8 skgate9 skgate10 +$frame skgate11 skgate12 skgate13 skgate14 skgate15 +$frame skgate16 skgate17 skgate18 skgate19 skgate20 +$frame skgate21 skgate22 skgate23 skgate24 skgate25 +$frame skgate26 skgate27 skgate28 skgate29 skgate30 + +// Frame 46 - 57 +$frame skpain1 skpain2 skpain3 skpain4 skpain5 +$frame skpain6 skpain7 skpain8 skpain9 skpain10 +$frame skpain11 skpain12 + +// Frame 58 - 69 +$frame skredi1 skredi2 skredi3 skredi4 skredi5 +$frame skredi6 skredi7 skredi8 skredi9 skredi10 +$frame skredi11 skredi12 + +// +//$frame skspel1 skspel2 skspel3 skspel4 skspel5 +//$frame skspel6 skspel7 skspel8 skspel9 skspel10 +//$frame skspel11 skspel12 skspel13 skspel14 skspel15 +//$frame skspel16 skspel17 skspel18 skspel19 skspel20 +//$frame skspel21 skspel22 skspel23 skspel24 skspel25 +//$frame skspel26 skspel27 skspel28 skspel29 skspel30 +//$frame skspel31 + +// Frame 70 - 84 +$frame skspel2 skspel4 +$frame skspel6 skspel8 skspel10 +$frame skspel12 skspel14 +$frame skspel16 skspel18 skspel20 +$frame skspel22 skspel24 +$frame skspel26 skspel28 skspel30 + + +// +//$frame sktele1 sktele2 sktele3 sktele4 sktele5 +//$frame sktele6 sktele7 sktele8 sktele9 sktele10 +//$frame sktele11 sktele12 sktele13 sktele14 sktele15 +//$frame sktele16 sktele17 sktele18 sktele19 sktele20 +//$frame sktele21 sktele22 sktele23 sktele24 sktele25 +//$frame sktele26 sktele27 sktele28 sktele29 sktele30 +//$frame sktele31 + +$frame sktele2 sktele4 +$frame sktele6 sktele8 sktele10 +$frame sktele12 sktele14 +$frame sktele16 sktele18 sktele20 +$frame sktele22 sktele24 +$frame sktele26 sktele28 sktele30 +// +$frame sktran1 sktran2 sktran3 sktran4 sktran5 +$frame sktran6 sktran7 + +// +$frame skwait1 skwait2 skwait10 skwait11 skwait12 +$frame skwait13 skwait14 skwait15 skwait16 skwait17 +$frame skwait18 skwait19 skwait20 skwait21 skwait22 +$frame skwait23 skwait24 skwait25 skwait26 + +// +$frame skwalk1 skwalk2 skwalk3 skwalk4 skwalk5 +$frame skwalk6 skwalk7 skwalk8 skwalk9 skwalk10 +$frame skwalk11 skwalk12 skwalk13 skwalk14 skwalk15 +$frame skwalk16 skwalk17 skwalk18 skwalk19 skwalk20 +$frame skwalk21 skwalk22 skwalk23 skwalk24 + + +void skullwiz_walk(void); +void skullwiz_run(void); +void skullwiz_melee(void); +void skullwiz_blink(void); +void skullwiz_push (void); +void skullwiz_missile_init (void); + +float SKULLBOOK =0; +float SKULLHEAD =1; + +float() SkullFacingIdeal = +{ + local float delta; + + delta = anglemod(self.angles_y - self.ideal_yaw); + if (delta > 25 && delta < 335) + return FALSE; + return TRUE; +}; + +void phase_init (void) +{ + vector spot1,newangle; + float loop_cnt,forward; + + trace_fraction =0; + loop_cnt = 0; + do + { + newangle = self.angles; + newangle_y = random(0,360); + makevectors (newangle); + forward = random(40,100); + spot1 = self.origin + v_forward * forward; + tracearea (spot1,spot1 + v_up * 80,'-32 -32 -10','32 32 46',FALSE,self); + if ((trace_fraction == 1.0) && (!trace_allsolid)) // Check there is a floor at the new spot + { + traceline (spot1, spot1 + (v_up * -4) , FALSE, self); + + if (trace_fraction ==1) // Didn't hit anything? There was no floor + trace_fraction = 0; // So it will loop + else + trace_fraction = 1; // So it will end loop + } + else + trace_fraction = 0; + + loop_cnt += 1; + + if (loop_cnt > 500) // No endless loops + { + self.nextthink = time + 2; + return; + } + + } while (trace_fraction != 1.0); + + self.origin = spot1; +} + +float check_defense_blink () +{ +vector spot1,spot2,dangerous_dir; +float dot; + if(!self.enemy) + return FALSE; + + if(!visible(self.enemy)) + return FALSE; + + if(self.enemy.last_attack