]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/samual/flyingspectators'
authormand1nga <mand1nga@xonotic.org>
Sun, 21 Aug 2011 03:10:17 +0000 (00:10 -0300)
committermand1nga <mand1nga@xonotic.org>
Sun, 21 Aug 2011 03:10:17 +0000 (00:10 -0300)
22 files changed:
defaultXonotic.cfg
qcsrc/client/View.qc
qcsrc/client/gibs.qc
qcsrc/client/movetypes.qc
qcsrc/common/urllib.qc [new file with mode: 0644]
qcsrc/common/urllib.qh [new file with mode: 0644]
qcsrc/server/assault.qc
qcsrc/server/bot/aim.qc
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/bot/havocbot/role_assault.qc [new file with mode: 0644]
qcsrc/server/bot/havocbot/role_ctf.qc
qcsrc/server/bot/havocbot/roles.qc
qcsrc/server/bot/navigation.qc
qcsrc/server/cl_player.qc
qcsrc/server/func_breakable.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/playerstats.qc
qcsrc/server/progs.src
qcsrc/server/t_plats.qc
qcsrc/server/w_rifle.qc
qcsrc/server/w_shotgun.qc

index f53776e84aca50d918b77336f4095617efdec484..29654fe5cf0767375a47f67ed06e55de0c9bc505 100644 (file)
@@ -450,8 +450,8 @@ set bot_ai_aimskill_offset 0.3 "Amount of error induced to the bots aim"
 set bot_ai_aimskill_think 1 "Aiming velocity. Use values below 1 for slower aiming"
 set bot_ai_custom_weapon_priority_distances "300 850"  "Define close and far distances in any order. Based on the distance to the enemy bots will choose different weapons"
 set bot_ai_custom_weapon_priority_far   "minstanex nex rifle electro rocketlauncher grenadelauncher hagar hlac crylink laser uzi fireball seeker shotgun tuba minelayer"       "Desired weapons for far distances ordered by priority"
-set bot_ai_custom_weapon_priority_mid   "minstanex rocketlauncher nex fireball seeker grenadelauncher electro uzi rifle crylink hlac hagar shotgun laser tuba minelayer"       "Desired weapons for middle distances ordered by priority"
-set bot_ai_custom_weapon_priority_close "minstanex shotgun nex uzi hlac tuba seeker hagar crylink grenadelauncher electro rifle rocketlauncher laser fireball minelayer"       "Desired weapons for close distances ordered by priority"
+set bot_ai_custom_weapon_priority_mid   "minstanex rocketlauncher nex fireball seeker grenadelauncher electro uzi crylink hlac hagar shotgun laser rifle tuba minelayer"       "Desired weapons for middle distances ordered by priority"
+set bot_ai_custom_weapon_priority_close "minstanex shotgun nex uzi hlac tuba seeker hagar crylink grenadelauncher electro rocketlauncher laser fireball rifle minelayer"       "Desired weapons for close distances ordered by priority"
 set bot_ai_weapon_combo 1      "Enable bots to do weapon combos"
 set bot_ai_weapon_combo_threshold 0.4  "Try to make a combo N seconds after the last attack"
 set bot_ai_friends_aware_pickup_radius "500"   "Bots will not pickup items if a team mate is this distance near the item"
index a5858bd49882fff3f2da7f8238c5ba4d28ccce2f..cb077390c3bead6dc6c3b35ce000594d07bd5334 100644 (file)
@@ -348,6 +348,7 @@ void CSQC_RAPTOR_HUD();
 vector freeze_org, freeze_ang;
 entity nightvision_noise, nightvision_noise2;
 
+#define MAX_TIME_DIFF 5
 float pickup_crosshair_time, pickup_crosshair_size;
 float hit_time, typehit_time;
 float nextsound_hit_time, nextsound_typehit_time;
@@ -957,13 +958,17 @@ void CSQC_UpdateView(float w, float h)
        hit_time = getstatf(STAT_HIT_TIME);
        if(hit_time > nextsound_hit_time && autocvar_cl_hitsound)
        {
-               sound(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE);
+               if(time - hit_time < MAX_TIME_DIFF) // don't play the sound if it's too old.
+                       sound(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE);
+                       
                nextsound_hit_time = time + autocvar_cl_hitsound_antispam_time;
        }
        typehit_time = getstatf(STAT_TYPEHIT_TIME);
-       if(typehit_time > nextsound_typehit_time)
+       if(typehit_time > nextsound_typehit_time) 
        {
-               sound(world, CH_INFO, "misc/typehit.wav", VOL_BASE, ATTN_NONE);
+               if(time - typehit_time < MAX_TIME_DIFF) // don't play the sound if it's too old.
+                       sound(world, CH_INFO, "misc/typehit.wav", VOL_BASE, ATTN_NONE);
+                       
                nextsound_typehit_time = time + autocvar_cl_hitsound_antispam_time;
        }
 
@@ -1110,10 +1115,14 @@ void CSQC_UpdateView(float w, float h)
 
                        if(autocvar_crosshair_pickup)
                        {
-                               if(pickup_crosshair_time < getstatf(STAT_LAST_PICKUP))
+                               float stat_pickup_time = getstatf(STAT_LAST_PICKUP);
+                               
+                               if(pickup_crosshair_time < stat_pickup_time)
                                {
-                                       pickup_crosshair_size = 1;
-                                       pickup_crosshair_time = getstatf(STAT_LAST_PICKUP);
+                                       if(time - stat_pickup_time < MAX_TIME_DIFF) // don't trigger the animation if it's too old
+                                               pickup_crosshair_size = 1;
+                                               
+                                       pickup_crosshair_time = stat_pickup_time;
                                }
 
                                if(pickup_crosshair_size > 0)
@@ -1124,13 +1133,14 @@ void CSQC_UpdateView(float w, float h)
                                wcross_scale += sin(pickup_crosshair_size) * autocvar_crosshair_pickup;
                        }
 
-                       vector hitindication_color;
                        if(autocvar_crosshair_hitindication)
                        {
-                               hitindication_color = stov(autocvar_crosshair_hitindication_color);
+                               vector hitindication_color = stov(autocvar_crosshair_hitindication_color);
                                if(hitindication_crosshair_time < hit_time)
                                {
-                                       hitindication_crosshair_size = 1;
+                                       if(time - hit_time < MAX_TIME_DIFF) // don't trigger the animation if it's too old
+                                               hitindication_crosshair_size = 1;
+                                               
                                        hitindication_crosshair_time = hit_time;
                                }
 
index 4041bacc1b0ea6921f1cdd08d95750b03c9e5878..409f8094264abd9c943250431f109ad246a857d5 100644 (file)
@@ -103,7 +103,7 @@ void Gib_Draw()
        }
 }
 
-void TossGib (string mdlname, vector org, vector vconst, vector vrand, float specnum, float destroyontouch, float issilent)
+void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, float specnum, float destroyontouch, float issilent)
 {
        entity gib;
 
@@ -124,6 +124,13 @@ void TossGib (string mdlname, vector org, vector vconst, vector vrand, float spe
        else
                gib.move_touch = SUB_RemoveOnNoImpact;
 
+       // don't spawn gibs inside solid - just don't
+       if(org != safeorg)
+       {
+               tracebox(safeorg, gib.mins, gib.maxs, org, MOVE_NOMONSTERS, gib);
+               org = trace_endpos;
+       }
+
        gib.move_origin = gib.origin = org;
        gib.move_velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
        gib.move_avelocity = prandomvec() * vlen(gib.move_velocity);
@@ -195,37 +202,37 @@ void Ent_GibSplash(float isNew)
                                sound (self, CH_PAIN, "misc/gib.wav", VOL_BASE, ATTN_NORM);
 
                        if(prandom() < amount)
-                               TossGib ("models/gibs/eye.md3", org, vel, prandomvec() * 150, specnum, 0, issilent);
+                               TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent);
                        new_te_bloodshower(particleeffectnum(strcat(specstr, "bloodshower")), org, 1200, amount);
                        if(prandom() < amount)
-                               TossGib ("models/gibs/bloodyskull.md3", org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent);
+                               TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent);
 
                        for(c = 0; c < amount; ++c)
                        {
                                randomvalue = amount - c;
 
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/arm.md3", org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
+                                       TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/arm.md3", org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
+                                       TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chest.md3", org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
+                                       TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/smallchest.md3", org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
+                                       TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/leg1.md3", org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
+                                       TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/leg2.md3", org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
+                                       TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
 
                                // these splat on impact
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
                                if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
                        }
                        break;
                case 0x02:
@@ -233,7 +240,7 @@ void Ent_GibSplash(float isNew)
                        break;
                case 0x03:
                        if(prandom() < amount)
-                               TossGib ("models/gibs/chunk.mdl", org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization?
+                               TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization?
                        break;
                case 0x81:
                        pointparticles(particleeffectnum(strcat(gentle_prefix, "damage_dissolve")), org, vel, amount);
index 4dcdae90bf1bb7e5b85aad0c472afbb450d5c170..49f35d891260d8a9b229a8561165b7055b58166a 100644 (file)
@@ -2,7 +2,7 @@ float STAT_MOVEFLAGS = 225;
 float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
 #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
 
-.entity move_groundentity;
+.entity move_groundentity; // FIXME add move_groundnetworkentity?
 .float move_suspendedinair;
 .float move_didgravity;
 
diff --git a/qcsrc/common/urllib.qc b/qcsrc/common/urllib.qc
new file mode 100644 (file)
index 0000000..54bcefe
--- /dev/null
@@ -0,0 +1,282 @@
+// files (-1 for URL)
+.float url_fh;
+
+// URLs
+.string url_url;
+.float url_wbuf;
+.float url_wbufpos;
+.float url_rbuf;
+.float url_rbufpos;
+.float url_id;
+.url_ready_func url_ready;
+.entity url_ready_pass;
+
+entity url_fromid[NUM_URL_ID];
+float autocvar__urllib_nextslot;
+
+float url_URI_Get_Callback(float id, float status, string data)
+{
+       if(id < MIN_URL_ID)
+               return 0;
+       id -= MIN_URL_ID;
+       if(id >= NUM_URL_ID)
+               return 0;
+       entity e;
+       e = url_fromid[id];
+       if(!e)
+               return 0;
+       if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
+       {
+               print(sprintf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url));
+               return 0;
+       }
+
+       // whatever happens, we will remove the URL from the list of IDs
+       url_fromid[id] = world;
+
+       if(status == 0)
+       {
+               // WE GOT DATA!
+               float n, i;
+               n = tokenizebyseparator(data, "\n");
+               e.url_rbuf = buf_create();
+               if(e.url_rbuf < 0)
+               {
+                       print("url_URI_Get_Callback: out of memory in buf_create\n");
+                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
+                       strunzone(e.url_url);
+                       remove(e);
+                       return 1;
+               }
+               e.url_rbufpos = 0;
+               if(e.url_rbuf < 0)
+               {
+                       print("url_URI_Get_Callback: out of memory in buf_create\n");
+                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
+                       strunzone(e.url_url);
+                       remove(e);
+                       return 1;
+               }
+               for(i = 0; i < n; ++i)
+                       bufstr_set(e.url_rbuf, i, argv(i));
+               e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
+               return 1;
+       }
+       else
+       {
+               // an ERROR
+               e.url_ready(e, e.url_ready_pass, -status);
+               strunzone(e.url_url);
+               remove(e);
+               return 1;
+       }
+}
+
+void url_fopen(string url, float mode, url_ready_func rdy, entity pass)
+{
+       entity e;
+       float i;
+       if(strstrofs(url, "://", 0) >= 0)
+       {
+               switch(mode)
+               {
+                       case FILE_WRITE:
+                       case FILE_APPEND:
+                               // collect data to a stringbuffer for a POST request
+                               // attempts to close will result in a reading handle
+
+                               // create a writing end that does nothing yet
+                               e = spawn();
+                               e.classname = "url_fopen_file";
+                               e.url_url = strzone(url);
+                               e.url_fh = -1;
+                               e.url_wbuf = buf_create();
+                               if(e.url_wbuf < 0)
+                               {
+                                       print("url_fopen: out of memory in buf_create\n");
+                                       rdy(e, pass, URL_READY_ERROR);
+                                       strunzone(e.url_url);
+                                       remove(e);
+                                       return;
+                               }
+                               e.url_wbufpos = 0;
+                               e.url_rbuf = -1;
+                               rdy(e, pass, URL_READY_CANWRITE);
+                               break;
+
+                       case FILE_READ:
+                               // read data only
+
+                               // get slot for HTTP request
+                               for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+                                       if(url_fromid[i] == world)
+                                               break;
+                               if(i >= NUM_URL_ID)
+                               {
+                                       for(i = 0; i < autocvar__urllib_nextslot; ++i)
+                                               if(url_fromid[i] == world)
+                                                       break;
+                                       if(i >= autocvar__urllib_nextslot)
+                                       {
+                                               print("url_fopen: too many concurrent requests\n");
+                                               rdy(world, pass, URL_READY_ERROR);
+                                               return;
+                                       }
+                               }
+
+                               // GET the data
+                               if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
+                               {
+                                       print("url_fopen: failure in crypto_uri_postbuf\n");
+                                       rdy(world, pass, URL_READY_ERROR);
+                                       return;
+                               }
+
+                               // Make a dummy handle object (no buffers at
+                               // all). Wait for data to come from the
+                               // server, then call the callback
+                               e = spawn();
+                               e.classname = "url_fopen_file";
+                               e.url_url = strzone(url);
+                               e.url_fh = -1;
+                               e.url_rbuf = -1;
+                               e.url_wbuf = -1;
+                               e.url_ready = rdy;
+                               e.url_ready_pass = pass;
+                               e.url_id = i;
+                               url_fromid[i] = e;
+
+                               // make sure this slot won't be reused quickly even on map change
+                               cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
+                               break;
+               }
+       }
+       else
+       {
+               float fh;
+               fh = fopen(url, mode);
+               if(fh < 0)
+               {
+                       rdy(world, pass, URL_READY_ERROR);
+                       return;
+               }
+               else
+               {
+                       e = spawn();
+                       e.classname = "url_fopen_file";
+                       e.url_fh = fh;
+                       if(mode == FILE_READ)
+                               rdy(e, pass, URL_READY_CANREAD);
+                       else
+                               rdy(e, pass, URL_READY_CANWRITE);
+               }
+       }
+}
+
+// close a file
+void url_fclose(entity e, url_ready_func rdy, entity pass)
+{
+       float i;
+
+       if(e.url_fh < 0)
+       {
+               // closing an URL!
+               if(e.url_wbuf >= 0)
+               {
+                       // we are closing the write end (HTTP POST request)
+
+                       // get slot for HTTP request
+                       for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+                               if(url_fromid[i] == world)
+                                       break;
+                       if(i >= NUM_URL_ID)
+                       {
+                               for(i = 0; i < autocvar__urllib_nextslot; ++i)
+                                       if(url_fromid[i] == world)
+                                               break;
+                               if(i >= autocvar__urllib_nextslot)
+                               {
+                                       print("url_fclose: too many concurrent requests\n");
+                                       rdy(e, pass, URL_READY_ERROR);
+                                       buf_del(e.url_wbuf);
+                                       strunzone(e.url_url);
+                                       remove(e);
+                                       return;
+                               }
+                       }
+
+                       // POST the data
+                       if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
+                       {
+                               print("url_fclose: failure in crypto_uri_postbuf\n");
+                               rdy(e, pass, URL_READY_ERROR);
+                               buf_del(e.url_wbuf);
+                               strunzone(e.url_url);
+                               remove(e);
+                               return;
+                       }
+
+                       // delete write end. File handle is now in unusable
+                       // state. Wait for data to come from the server, then
+                       // call the callback
+                       buf_del(e.url_wbuf);
+                       e.url_wbuf = -1;
+                       e.url_ready = rdy;
+                       e.url_ready_pass = pass;
+                       e.url_id = i;
+                       url_fromid[i] = e;
+
+                       // make sure this slot won't be reused quickly even on map change
+                       cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
+               }
+               else
+               {
+                       // we have READ all data, just close
+                       rdy(e, pass, URL_READY_CLOSED);
+                       buf_del(e.url_rbuf);
+                       strunzone(e.url_url);
+                       remove(e);
+               }
+       }
+       else
+       {
+               // file
+               fclose(e.url_fh);
+               rdy(e, pass, URL_READY_CLOSED); // closing creates no reading handle
+               remove(e);
+       }
+}
+
+// with \n (blame FRIK_FILE)
+string url_fgets(entity e)
+{
+       if(e.url_fh < 0)
+       {
+               // curl
+               string s;
+               s = bufstr_get(e.url_rbuf, e.url_rbufpos);
+               e.url_rbufpos += 1;
+               return s;
+       }
+       else
+       {
+               // file
+               return fgets(e.url_fh);
+       }
+}
+
+// without \n (blame FRIK_FILE)
+void url_fputs(entity e, string s)
+{
+       if(e.url_fh < 0)
+       {
+               // curl
+               bufstr_set(e.url_wbuf, e.url_wbufpos, s);
+               e.url_wbufpos += 1;
+       }
+       else
+       {
+               // file
+               fputs(e.url_fh, s);
+       }
+}
diff --git a/qcsrc/common/urllib.qh b/qcsrc/common/urllib.qh
new file mode 100644 (file)
index 0000000..a7735ed
--- /dev/null
@@ -0,0 +1,16 @@
+float URL_READY_ERROR    = -1;
+float URL_READY_CLOSED   =  0;
+float URL_READY_CANWRITE =  1;
+float URL_READY_CANREAD  =  2;
+// errors: -1, or negative HTTP status code
+typedef void(entity handle, entity pass, float status) url_ready_func;
+
+void url_fopen(string url, float mode, url_ready_func rdy, entity pass);
+void url_fclose(entity e, url_ready_func rdy, entity pass);
+string url_fgets(entity e);
+void url_fputs(entity e, string s);
+
+// returns true if handled
+float url_URI_Get_Callback(float id, float status, string data);
+#define MIN_URL_ID 128
+#define NUM_URL_ID 64
index 85009dd830967c11f8b9d1a3c08953db803f970d..517da81684928019729e385b6feb244b32963021 100644 (file)
@@ -103,7 +103,7 @@ void assault_objective_decrease_use() {
                                                centerprint(player, s);
                                        }
                                }
-                                       
+
                                oldactivator = activator;
                                activator = oldself;
                                        SUB_UseTargets();
@@ -207,6 +207,7 @@ void spawnfunc_func_assault_destructible() {
                return;
        }
        self.spawnflags = 3;
+       self.classname = "func_assault_destructible";
        if(assault_attacker_team == COLOR_TEAM1) {
                self.team = COLOR_TEAM2;
        } else {
@@ -271,7 +272,7 @@ void assault_roundstart_use() {
        activator = self;
        SUB_UseTargets();
 
-       
+
 #ifdef TTURRETS_ENABLED
        entity ent, oldself;
 
@@ -315,7 +316,7 @@ void spawnfunc_target_assault_roundstart() {
 // reset objectives, toggle spawnpoints, reset triggers, ...
 void vehicles_clearrturn();
 void vehicles_spawn();
-void assault_new_round() 
+void assault_new_round()
 {
     entity oldself;
        //bprint("ASSAULT: new round\n");
@@ -325,9 +326,9 @@ void assault_new_round()
     FOR_EACH_PLAYER(self)
     {
         if(self.vehicle)
-            vehicles_exit(VHEF_RELESE);        
+            vehicles_exit(VHEF_RELESE);
     }
-    
+
     self = findchainflags(vehicle_flags, VHF_ISVEHICLE);
     while(self)
     {
@@ -360,7 +361,7 @@ void assault_new_round()
                                ent.team_saved = COLOR_TEAM1;
                }
        }
-       
+
        // reset the level with a countdown
        cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
        ReadyRestartForce(); // sets game_starttime
index 699748fdae58401b0fe3d9002977e88ac17f7993..b678bf1b660de2a9920d29ebc5e8af7a2ef554ab 100644 (file)
@@ -320,7 +320,7 @@ vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, flo
 
 float bot_aim(float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
 {
-       local float f, r;
+       local float f, r, hf, distanceratio;
        local vector v;
        /*
        eprint(self);
@@ -330,6 +330,10 @@ float bot_aim(float shotspeed, float shotspeedupward, float maxshottime, float a
        dprint(", ", ftos(applygravity));
        dprint(");\n");
        */
+
+       hf = self.dphitcontentsmask;
+       self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
+
        shotspeed *= g_weaponspeedfactor;
        shotspeedupward *= g_weaponspeedfactor;
        if (!shotspeed)
@@ -346,15 +350,18 @@ float bot_aim(float shotspeed, float shotspeedupward, float maxshottime, float a
        shotorg = self.origin + self.view_ofs;
        shotdir = v_forward;
        v = bot_shotlead(self.bot_aimtargorigin, self.bot_aimtargvelocity, shotspeed, self.bot_aimlatency);
-       local float distanceratio;
-       distanceratio =sqrt(bound(0,skill,10000))*0.3*(vlen(v-shotorg)-100)/autocvar_bot_ai_aimskill_firetolerance_distdegrees;
+       distanceratio = sqrt(bound(0,skill,10000))*0.3*(vlen(v-shotorg)-100)/autocvar_bot_ai_aimskill_firetolerance_distdegrees;
        distanceratio = bound(0,distanceratio,1);
        r =  (autocvar_bot_ai_aimskill_firetolerance_maxdegrees-autocvar_bot_ai_aimskill_firetolerance_mindegrees)
                * (1-distanceratio) + autocvar_bot_ai_aimskill_firetolerance_mindegrees;
        if (applygravity && self.bot_aimtarg)
        {
                if (!findtrajectorywithleading(shotorg, '0 0 0', '0 0 0', self.bot_aimtarg, shotspeed, shotspeedupward, maxshottime, 0, self))
+               {
+                       self.dphitcontentsmask = hf;
                        return FALSE;
+               }
+
                f = bot_aimdir(findtrajectory_velocity - shotspeedupward * '0 0 1', r);
        }
        else
@@ -370,10 +377,14 @@ float bot_aim(float shotspeed, float shotspeedupward, float maxshottime, float a
                if (trace_fraction < 1)
                if (trace_ent != self.enemy)
                if (!bot_shouldattack(trace_ent))
+               {
+                       self.dphitcontentsmask = hf;
                        return FALSE;
+               }
        }
 
        //if (r > maxshottime * shotspeed)
        //      return FALSE;
+       self.dphitcontentsmask = hf;
        return TRUE;
 };
index 1d9054952d24bbdde4d63981bc5a86689f3a44f4..113d318506b456d478aa3b7ab62701ba0347cb05 100644 (file)
@@ -4,6 +4,7 @@
 #include "role_keyhunt.qc"
 #include "role_freezetag.qc"
 #include "role_keepaway.qc"
+#include "role_assault.qc"
 #include "roles.qc"
 
 void havocbot_ai()
@@ -488,7 +489,7 @@ void havocbot_movetogoal()
        // Handling of jump pads
        if(self.jumppadcount)
        {
-               // If got stuck on the jump pad try to reach the farthest visible item
+               // If got stuck on the jump pad try to reach the farthest visible waypoint
                if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
                {
                        if(fabs(self.velocity_z)<50)
@@ -496,10 +497,8 @@ void havocbot_movetogoal()
                                local entity head, newgoal;
                                local float distance, bestdistance;
 
-                               for (head = findchainfloat(bot_pickup, TRUE); head; head = head.chain)
+                               for (head = findchain(classname, "waypoint"); head; head = head.chain)
                                {
-                                       if(head.classname=="worldspawn")
-                                               continue;
 
                                        distance = vlen(head.origin - self.origin);
                                        if(distance>1000)
@@ -533,11 +532,13 @@ void havocbot_movetogoal()
                {
                        if(self.velocity_z>0)
                        {
-                               local float threshold;
+                               float threshold, sxy;
+                               vector velxy = self.velocity; velxy_z = 0;
+                               sxy = vlen(velxy);
                                threshold = maxspeed * 0.2;
-                               if(fabs(self.velocity_x) < threshold  &&  fabs(self.velocity_y) < threshold)
+                               if(sxy < threshold)
                                {
-                                       dprint("Warning: ", self.netname, " got stuck on a jumppad, trying to get out of it now\n");
+                                       dprint("Warning: ", self.netname, " got stuck on a jumppad (velocity in xy is ", ftos(sxy), "), trying to get out of it now\n");
                                        self.aistatus |= AI_STATUS_OUT_JUMPPAD;
                                }
                                return;
@@ -862,7 +863,7 @@ void havocbot_movetogoal()
 void havocbot_chooseenemy()
 {
        local entity head, best, head2;
-       local float rating, bestrating, i, f;
+       local float rating, bestrating, i, hf;
        local vector eye, v;
        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(self))
        {
@@ -907,7 +908,13 @@ void havocbot_chooseenemy()
        bestrating = 100000000;
        head = head2 = findchainfloat(bot_attack, TRUE);
 
+       // Backup hit flags
+       hf = self.dphitcontentsmask;
+
        // Search for enemies, if no enemy can be seen directly try to look through transparent objects
+
+       self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
+
        for(;;)
        {
                while (head)
@@ -936,16 +943,14 @@ void havocbot_chooseenemy()
                        break;
 
                // Set flags to see through transparent objects
-               f = self.dphitcontentsmask;
-               self.dphitcontentsmask = DPCONTENTS_OPAQUE;
+               self.dphitcontentsmask |= DPCONTENTS_OPAQUE;
 
                head = head2;
                ++i;
        }
 
-       // Restore hit flags if needed
-       if(i)
-               self.dphitcontentsmask = f;
+       // Restore hit flags
+       self.dphitcontentsmask = hf;
 
        self.enemy = best;
        self.havocbot_stickenemy = TRUE;
diff --git a/qcsrc/server/bot/havocbot/role_assault.qc b/qcsrc/server/bot/havocbot/role_assault.qc
new file mode 100644 (file)
index 0000000..5c0be47
--- /dev/null
@@ -0,0 +1,208 @@
+#define HAVOCBOT_AST_ROLE_NONE                 0
+#define HAVOCBOT_AST_ROLE_DEFENSE      2
+#define HAVOCBOT_AST_ROLE_OFFENSE      4
+
+.float havocbot_role_flags;
+.float havocbot_attack_time;
+
+.void() havocbot_role;
+.void() havocbot_previous_role;
+
+void() havocbot_role_ast_defense;
+void() havocbot_role_ast_offense;
+.entity havocbot_ast_target;
+
+void(entity bot) havocbot_ast_reset_role;
+
+void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
+void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
+
+void havocbot_goalrating_ast_targets(float ratingscale)
+{
+       entity ad, best, pl, wp, tod;
+       float radius, found, bestvalue, c;
+       vector p;
+
+       ad = findchain(classname, "func_assault_destructible");
+
+       for (; ad; ad = ad.chain)
+       {
+               if (ad.target == "")
+                       continue;
+
+               if not(ad.bot_attack)
+                       continue;
+
+               found = FALSE;
+               for(tod = world; (tod = find(tod, targetname, ad.target)); )
+               {
+                       if(tod.classname == "target_objective_decrease")
+                       {
+                               if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE)
+                               {
+                               //      dprint(etos(ad),"\n");
+                                       found = TRUE;
+                                       break;
+                               }
+                       }
+               }
+
+               if(!found)
+               {
+               ///     dprint("target not found\n");
+                       continue;
+               }
+               /// dprint("target #", etos(ad), " found\n");
+
+
+               p = 0.5 * (ad.absmin + ad.absmax);
+       //      dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n");
+       //      te_knightspike(p);
+       //      te_lightning2(world, '0 0 0', p);
+
+               // Find and rate waypoints around it
+               found = FALSE;
+               best = world;
+               bestvalue = 99999999999;
+               for(radius=0; radius<1500 && !found; radius+=500)
+               {
+                       for(wp=findradius(p, radius); wp; wp=wp.chain)
+                       {
+                               if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
+                               if(wp.classname=="waypoint")
+                               if(checkpvs(wp.origin, ad))
+                               {
+                                       found = TRUE;
+                                       if(wp.cnt<bestvalue)
+                                       {
+                                               best = wp;
+                                               bestvalue = wp.cnt;
+                                       }
+                               }
+                       }
+               }
+
+               if(best)
+               {
+               ///     dprint("waypoints around target were found\n");
+               //      te_lightning2(world, '0 0 0', best.origin);
+               //      te_knightspike(best.origin);
+
+                       navigation_routerating(best, ratingscale, 4000);
+                       best.cnt += 1;
+
+                       self.havocbot_attack_time = 0;
+
+                       if(checkpvs(self.view_ofs,ad))
+                       if(checkpvs(self.view_ofs,best))
+                       {
+                       //      dprint("increasing attack time for this target\n");
+                               self.havocbot_attack_time = time + 2;
+                       }
+               }
+       }
+}
+
+void havocbot_role_ast_offense()
+{
+       if(self.deadflag != DEAD_NO)
+       {
+               self.havocbot_attack_time = 0;
+               havocbot_ast_reset_role(self);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!self.havocbot_role_timeout)
+               self.havocbot_role_timeout = time + 120;
+
+       if (time > self.havocbot_role_timeout)
+       {
+               havocbot_ast_reset_role(self);
+               return;
+       }
+
+       if(self.havocbot_attack_time>time)
+               return;
+
+       if (self.bot_strategytime < time)
+       {
+               navigation_goalrating_start();
+               havocbot_goalrating_enemyplayers(20000, self.origin, 650);
+               havocbot_goalrating_ast_targets(20000);
+               havocbot_goalrating_items(15000, self.origin, 10000);
+               navigation_goalrating_end();
+
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+       }
+};
+
+void havocbot_role_ast_defense()
+{
+       if(self.deadflag != DEAD_NO)
+       {
+               self.havocbot_attack_time = 0;
+               havocbot_ast_reset_role(self);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!self.havocbot_role_timeout)
+               self.havocbot_role_timeout = time + 120;
+
+       if (time > self.havocbot_role_timeout)
+       {
+               havocbot_ast_reset_role(self);
+               return;
+       }
+
+       if(self.havocbot_attack_time>time)
+               return;
+
+       if (self.bot_strategytime < time)
+       {
+               navigation_goalrating_start();
+               havocbot_goalrating_enemyplayers(20000, self.origin, 3000);
+               havocbot_goalrating_ast_targets(20000);
+               havocbot_goalrating_items(15000, self.origin, 10000);
+               navigation_goalrating_end();
+
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+       }
+};
+
+void havocbot_role_ast_setrole(entity bot, float role)
+{
+       switch(role)
+       {
+               case HAVOCBOT_AST_ROLE_DEFENSE:
+                       bot.havocbot_role = havocbot_role_ast_defense;
+                       bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_AST_ROLE_OFFENSE:
+                       bot.havocbot_role = havocbot_role_ast_offense;
+                       bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+       }
+};
+
+void havocbot_ast_reset_role(entity bot)
+{
+       local entity head;
+       local float c;
+
+       if(self.deadflag != DEAD_NO)
+               return;
+
+       if(bot.team==assault_attacker_team)
+               havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_OFFENSE);
+       else
+               havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_DEFENSE);
+};
+
+void havocbot_chooserole_ast()
+{
+       havocbot_ast_reset_role(self);
+};
index 201e6982a0ac892ec5215e2eca52e50566cf0aaf..f85f2ef64c3e8a0c0964d5d344eb6977ef1c300d 100644 (file)
@@ -146,7 +146,8 @@ void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
        if(mf.cnt == FLAG_BASE)
                return;
 
-       navigation_routerating(mf, ratingscale, 10000);
+       if(mf.tag_entity)
+               navigation_routerating(mf.tag_entity, ratingscale, 10000);
 };
 
 void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
@@ -203,6 +204,7 @@ void havocbot_role_ctf_setrole(entity bot, float role)
                        bot.havocbot_role = havocbot_role_ctf_carrier;
                        bot.havocbot_role_timeout = 0;
                        bot.havocbot_cantfindflag = time + 10;
+                       bot.bot_strategytime = 0;
                        break;
                case HAVOCBOT_CTF_ROLE_DEFENSE:
                        dprint("defense");
@@ -224,12 +226,14 @@ void havocbot_role_ctf_setrole(entity bot, float role)
                        bot.havocbot_previous_role = bot.havocbot_role;
                        bot.havocbot_role = havocbot_role_ctf_retriever;
                        bot.havocbot_role_timeout = time + 10;
+                       bot.bot_strategytime = 0;
                        break;
                case HAVOCBOT_CTF_ROLE_ESCORT:
                        dprint("escort");
                        bot.havocbot_previous_role = bot.havocbot_role;
                        bot.havocbot_role = havocbot_role_ctf_escort;
                        bot.havocbot_role_timeout = time + 30;
+                       bot.bot_strategytime = 0;
                        break;
        }
        dprint("\n");
index 18699a7bd6f310001cc50e3ac359d250a55f6e5a..4cf685ddb42f970afa43a58c88206333a99fcb76 100644 (file)
@@ -312,6 +312,8 @@ void havocbot_chooserole()
                havocbot_chooserole_ka();
        else if (g_freezetag)
                havocbot_chooserole_ft();
+       else if (g_assault)
+               havocbot_chooserole_ast();
        else // assume anything else is deathmatch
                havocbot_chooserole_dm();
 };
index 4f680284eec19ff96b3b6bcfbfa3477a04d9abd7..968e760b8b721caff6b71cd452af93dd183fe726 100644 (file)
@@ -891,6 +891,23 @@ void navigation_poptouchedgoals()
                }
        }
 
+       // If for some reason the bot is closer to the next goal, pop the current one
+       if(self.goalstack01)
+       if(vlen(self.goalcurrent.origin - self.origin) > vlen(self.goalstack01.origin - self.origin))
+       if(checkpvs(self.origin + self.view_ofs, self.goalstack01))
+       if(tracewalk(self, self.origin, self.mins, self.maxs, (self.goalstack01.absmin + self.goalstack01.absmax) * 0.5, bot_navigation_movemode))
+       {
+       ///     dprint("path optimized, removed a goal from the queue\n");
+               navigation_poproute();
+               // TODO this may also be a nice idea to do "early" (e.g. by
+               // manipulating the vlen() comparisons) to shorten paths in
+               // general - this would make bots walk more "on rails" than
+               // "zigzagging" which they currently do with sufficiently
+               // random-like waypoints, and thus can make a nice bot
+               // personality property
+       }
+
+
        // Loose goal touching check when running
        if(self.aistatus & AI_STATUS_RUNNING)
        if(self.goalcurrent.classname=="waypoint")
index 6f82d9f1043c7b30d21d98a6a2c52830944737ca..63ba50d5ba2bec255afafce011e1a96f283a944b 100644 (file)
@@ -13,23 +13,23 @@ void WeaponStats_Init()
 
 #define WEAPONSTATS_GETINDEX(awep,abot,vwep,vbot) (((vwep) + (awep) * (WEP_LAST - WEP_FIRST + 1) - (WEP_FIRST + WEP_FIRST * (WEP_LAST - WEP_FIRST + 1))) * 4 + (abot) * 2 + (vbot))
 
-void WeaponStats_Shutdown()
+void WeaponStats_ready(entity fh, entity pass, float status)
 {
-       float i, j, ibot, jbot, idx;
-       float fh;
+       float i, j, n, ibot, jbot, idx;
        vector v;
-       string prefix;
-       if(weaponstats_buffer < 0)
-               return;
-       prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t");
-       if(autocvar_sv_weaponstats_file != "")
+       string prefix, s;
+       switch(status)
        {
-               fh = fopen(autocvar_sv_weaponstats_file, FILE_APPEND);
-               if(fh >= 0)
-               {
-                       fputs(fh, "#begin statsfile\n");
-                       fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"));
-                       fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_changes)), "\n"));
+               case URL_READY_CANWRITE:
+                       // url_fopen returned, we can write
+                       prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t");
+                       url_fputs(fh, "#begin statsfile\n");
+                       url_fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"));
+                       url_fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_purechanges)), "\n"));
+                       url_fputs(fh, strcat("#cvar_purechanges ", ftos(cvar_purechanges_count), "\n"));
+                       n = tokenizebyseparator(cvar_purechanges, "\n");
+                       for(i = 0; i < n; ++i)
+                               url_fputs(fh, strcat("#cvar_purechange ", argv(i), "\n"));
                        for(i = WEP_FIRST; i <= WEP_LAST; ++i) for(ibot = 0; ibot <= 1; ++ibot)
                                for(j = WEP_FIRST; j <= WEP_LAST; ++j) for(jbot = 0; jbot <= 1; ++jbot)
                                {
@@ -38,17 +38,48 @@ void WeaponStats_Shutdown()
                                        if(v != '0 0 0')
                                        {
                                                //vector is: kills hits damage
-                                               fputs(fh, sprintf("%s%d %d\t%d %d\t", prefix, i, ibot, j, jbot));
-                                               fputs(fh, sprintf("%d %d %g\n", v_x, v_y, v_z));
+                                               url_fputs(fh, sprintf("%s%d %d\t%d %d\t", prefix, i, ibot, j, jbot));
+                                               url_fputs(fh, sprintf("%d %d %g\n", v_x, v_y, v_z));
                                        }
                                }
-                       fputs(fh, "#end\n\n");
-                       fclose(fh);
+                       url_fputs(fh, "#end\n\n");
+                       url_fclose(fh, WeaponStats_ready, world);
+                       buf_del(weaponstats_buffer);
+                       weaponstats_buffer = -1;
+                       break;
+               case URL_READY_CANREAD:
+                       // url_fclose is processing, we got a response for writing the data
+                       // this must come from HTTP
+                       print("Got response from weapon stats server:\n");
+                       while((s = url_fgets(fh)))
+                               print("  ", s, "\n");
+                       print("End of response.\n");
+                       url_fclose(fh, WeaponStats_ready, world);
+                       break;
+               case URL_READY_CLOSED:
+                       // url_fclose has finished
                        print("Weapon stats written\n");
-               }
+                       break;
+               case URL_READY_ERROR:
+               default:
+                       print("Weapon stats writing failed: ", ftos(status), "\n");
+                       break;
+       }
+}
+
+void WeaponStats_Shutdown()
+{
+       if(weaponstats_buffer < 0)
+               return;
+       if(autocvar_sv_weaponstats_file != "")
+       {
+               url_fopen(autocvar_sv_weaponstats_file, FILE_APPEND, WeaponStats_ready, world);
+       }
+       else
+       {
+               buf_del(weaponstats_buffer);
+               weaponstats_buffer = -1;
        }
-       buf_del(weaponstats_buffer);
-       weaponstats_buffer = -1;
 }
 
 void WeaponStats_LogItem(float awep, float abot, float vwep, float vbot, vector item)
index 1e474c0d641a34764fb55578f77614927f280f33..192e5cd7fb2e69f5b20b5708f4aec9af11224e28 100644 (file)
@@ -114,6 +114,7 @@ void func_breakable_behave_destroyed()
 {
        self.health = self.max_health;
        self.takedamage = DAMAGE_NO;
+       self.bot_attack = FALSE;
        self.event_damage = SUB_Null;
        self.state = 1;
        func_breakable_colormod();
@@ -128,6 +129,7 @@ void func_breakable_behave_restore()
                WaypointSprite_UpdateHealth(self.sprite, self.health);
        }
        self.takedamage = DAMAGE_AIM;
+       self.bot_attack = TRUE;
        self.event_damage = func_breakable_damage;
        self.state = 0;
        self.nextthink = 0; // cancel auto respawn
index fc29f2af83c0e575894e49b9babb0cf4bfbd56f8..1ba0a54eba6451f324d5555a876c51985e00d086 100644 (file)
@@ -295,6 +295,7 @@ void cvar_changes_init()
                BADPREFIX("developer_");
                BADPREFIX("g_ban_");
                BADPREFIX("g_chat_flood_");
+               BADPREFIX("g_playerstats_");
                BADPREFIX("g_voice_flood_");
                BADPREFIX("rcon_");
                BADPREFIX("settemp_");
@@ -307,10 +308,7 @@ void cvar_changes_init()
                BADPREFIX("sv_weaponstats_");
 
                // these can contain player IDs, so better hide
-               BADCVAR("g_forced_team_red");
-               BADCVAR("g_forced_team_blue");
-               BADCVAR("g_forced_team_yellow");
-               BADCVAR("g_forced_team_pink");
+               BADPREFIX("g_forced_team_");
 
                // mapinfo
                BADCVAR("fraglimit");
@@ -418,6 +416,7 @@ void cvar_changes_init()
                BADCVAR("g_ctf_ignore_frags");
                BADCVAR("g_ctf_win_mode");
                BADCVAR("g_domination_point_limit");
+               BADCVAR("g_friendlyfire");
                BADCVAR("g_fullbrightitems");
                BADCVAR("g_fullbrightplayers");
                BADCVAR("g_keyhunt_point_limit");
@@ -431,15 +430,17 @@ void cvar_changes_init()
                BADCVAR("g_maplist_votable_abstain");
                BADCVAR("g_maplist_votable_nodetail");
                BADCVAR("g_maplist_votable_suggestions");
+               BADCVAR("g_maxplayers");
                BADCVAR("g_minstagib");
+               BADCVAR("g_mirrordamage");
                BADCVAR("g_nexball_goallimit");
                BADCVAR("g_runematch_point_limit");
                BADCVAR("g_start_delay");
+               BADCVAR("g_warmup");
                BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
                BADCVAR("hostname");
                BADCVAR("log_file");
                BADCVAR("maxplayers");
-               BADCVAR("g_maxplayers");
                BADCVAR("minplayers");
                BADCVAR("net_address");
                BADCVAR("port");
@@ -467,10 +468,10 @@ void cvar_changes_init()
                BADCVAR("sv_vote_master_commands");
                BADCVAR("sv_vote_master_password");
                BADCVAR("sv_vote_simple_majority_factor");
+               BADCVAR("sys_ticrate");
+               BADCVAR("teamplay_mode");
                BADCVAR("timelimit_override");
-               BADCVAR("g_warmup");
                BADPREFIX("g_warmup_");
-               BADCVAR("teamplay_mode");
 
                if(autocvar_g_minstagib)
                {
@@ -1586,6 +1587,7 @@ void NextLevel()
        FOR_EACH_CLIENT(e)
                PlayerStats_AddGlobalInfo(e);
        PlayerStats_Shutdown();
+       WeaponStats_Shutdown();
 
        if(autocvar_sv_eventlog)
                GameLogEcho(":gameover");
index 1ca1768965b0fe3dcc6d9ca565ddb6a80628d84a..7a0257a068b33058814025f3419787e2e7d0c8fb 100644 (file)
@@ -2046,7 +2046,11 @@ void URI_Get_Callback(float id, float status, string data)
     dprint(data);
     dprint("\nEnd of data.\n");
 
-    if (id == URI_GET_DISCARD)
+    if(url_URI_Get_Callback(id, status, data))
+    {
+        // handled
+    }
+    else if (id == URI_GET_DISCARD)
     {
         // discard
     }
index c691d542bb63f2cf4bf44ec2c61ce009faee12c2..7f20b92454db5084718d1ca79df4a4cef219fb76 100644 (file)
@@ -284,10 +284,10 @@ void PlayerStats_AddGlobalInfo(entity p)
 
        // add global info!
        if(p.alivetime)
+       {
                PlayerStats_Event(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
-
-       if(p.alivetime)
-               PlayerStats_Event(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
+               p.alivetime = 0;
+       }
 
        db_put(playerstats_db, sprintf("%s:_netname", p.playerstats_id), ftos(p.playerid));
        
@@ -297,7 +297,7 @@ void PlayerStats_AddGlobalInfo(entity p)
     if(teamplay)
                db_put(playerstats_db, sprintf("%s:_team", p.playerstats_id), ftos(p.team));
 
-       if(p.alivetime > 0)
+       if(stof(db_get(playerstats_db, sprintf("%d:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
                PlayerStats_Event(p, PLAYERSTATS_JOINS, 1);
 
        strunzone(p.playerstats_id);
@@ -328,7 +328,7 @@ void PlayerStats_EndMatch(float finished)
 {
        entity p, winner;
     winner = PlayerScore_Sort(score_dummyfield);
-       FOR_EACH_PLAYER(p)
+       FOR_EACH_PLAYER(p) // spectators intentionally not included
        {
                PlayerScore_PlayerStats(p);
                PlayerStats_Accuracy(p);
index 58d40dbea8f66c07b94bc1f035ab3e1046daa681..c78b9f2fa5908c650ba76fd71cb0298146764599 100644 (file)
@@ -18,6 +18,7 @@ post-builtins.qh
 ../common/util.qh
 ../common/items.qh
 ../common/explosion_equation.qh
+../common/urllib.qh
 
 autocvars.qh
 constants.qh
@@ -132,6 +133,7 @@ vote.qc
 campaign.qc
 ../common/campaign_file.qc
 ../common/campaign_setup.qc
+../common/urllib.qc
 
 ../common/gamecommand.qc
 gamecommand.qc
index e2d801fa491fe9c011da08a22fea8ae1beccceac..ca87ede224ad45a1a67f401008ec253271c2a65f 100644 (file)
@@ -140,8 +140,9 @@ void plat_crush()
             plat_go_down ();
         else if (self.state == 3)
             plat_go_up ();
-        else
-            objerror ("plat_crush: bad self.state\n");
+       // when in other states, then the plat_crush event came delayed after
+       // plat state already had changed
+       // this isn't a bug per se!
     }
 };
 
index d89d44571d113daff23598475bc780c6e9f0d47c..02d859e0fdf854c734e8739111a8bf19aa5558b2 100644 (file)
@@ -116,7 +116,7 @@ float w_rifle(float req)
                        self.bot_secondary_riflemooth = 0;
                if(self.bot_secondary_riflemooth == 0)
                {
-                       if(bot_aim(autocvar_g_balance_rifle_primary_speed, 0, autocvar_g_balance_rifle_primary_lifetime, TRUE))
+                       if(bot_aim(autocvar_g_balance_rifle_primary_speed, 0, autocvar_g_balance_rifle_primary_lifetime, FALSE))
                        {
                                self.BUTTON_ATCK = TRUE;
                                if(random() < 0.01) self.bot_secondary_riflemooth = 1;
@@ -124,7 +124,7 @@ float w_rifle(float req)
                }
                else
                {
-                       if(bot_aim(autocvar_g_balance_rifle_secondary_speed, 0, autocvar_g_balance_rifle_secondary_lifetime, TRUE))
+                       if(bot_aim(autocvar_g_balance_rifle_secondary_speed, 0, autocvar_g_balance_rifle_secondary_lifetime, FALSE))
                        {
                                self.BUTTON_ATCK2 = TRUE;
                                if(random() < 0.03) self.bot_secondary_riflemooth = 0;
@@ -147,7 +147,7 @@ float w_rifle(float req)
                                self.rifle_accumulator += autocvar_g_balance_rifle_primary_burstcost;
                        }
                        if (self.BUTTON_ATCK2)
-                       {       
+                       {
                                if (autocvar_g_balance_rifle_secondary)
                                {
                     if(autocvar_g_balance_rifle_secondary_reload)
index b77ed92252eb640d7131ac40431caf54dfc9458e..9d80ff4a7b88c2318c78e7468b4ce816d108e32f 100644 (file)
@@ -113,7 +113,13 @@ float w_shotgun(float req)
                if(vlen(self.origin-self.enemy.origin) <= autocvar_g_balance_shotgun_secondary_melee_range)
                        self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE);
                else
-                       self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
+               {
+                       if(autocvar_g_antilag_bullets)
+                               self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
+                       else
+                               self.BUTTON_ATCK = bot_aim(autocvar_g_balance_shotgun_primary_speed, 0, 0.001, FALSE);
+               }
+
        else if (req == WR_THINK)
        {
                if(autocvar_g_balance_shotgun_reload_ammo && self.clip_load < autocvar_g_balance_shotgun_primary_ammo) // forced reload