+void SV_TouchAreaGrid(edict_t *ent, areanode_t *node)
+{
+ link_t *l, *next;
+ edict_t *touch;
+ areagrid_t *grid;
+ int old_self, old_other, igrid[3], igridmins[3], igridmaxs[3];
+
+ igridmins[0] = (int) ((ent->v->absmin[0] + sv_areagridbias[0]) * sv_areagridscale[0]);
+ igridmins[1] = (int) ((ent->v->absmin[1] + sv_areagridbias[1]) * sv_areagridscale[1]);
+ //igridmins[2] = (int) ((ent->v->absmin[2] + sv_areagridbias[2]) * sv_areagridscale[2]);
+ igridmaxs[0] = (int) ((ent->v->absmax[0] + sv_areagridbias[0]) * sv_areagridscale[0]) + 1;
+ igridmaxs[1] = (int) ((ent->v->absmax[1] + sv_areagridbias[1]) * sv_areagridscale[1]) + 1;
+ //igridmaxs[2] = (int) ((ent->v->absmax[2] + sv_areagridbias[2]) * sv_areagridscale[2]) + 1;
+ igridmins[0] = max(0, igridmins[0]);
+ igridmins[1] = max(0, igridmins[1]);
+ //igridmins[2] = max(0, igridmins[2]);
+ igridmaxs[0] = min(AREA_GRID, igridmaxs[0]);
+ igridmaxs[1] = min(AREA_GRID, igridmaxs[1]);
+ //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]);
+
+ for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
+ {
+ grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0];
+ for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
+ {
+ for (l = grid->trigger_edicts.next;l != &grid->trigger_edicts;l = next)
+ {
+ next = l->next;
+ touch = EDICT_FROM_AREA(l);
+ if (touch == ent)
+ continue;
+ if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
+ continue;
+ if (ent->v->absmin[0] > touch->v->absmax[0]
+ || ent->v->absmin[1] > touch->v->absmax[1]
+ || ent->v->absmin[2] > touch->v->absmax[2]
+ || ent->v->absmax[0] < touch->v->absmin[0]
+ || ent->v->absmax[1] < touch->v->absmin[1]
+ || ent->v->absmax[2] < touch->v->absmin[2])
+ continue;
+ old_self = pr_global_struct->self;
+ old_other = pr_global_struct->other;
+
+ pr_global_struct->self = EDICT_TO_PROG(touch);
+ pr_global_struct->other = EDICT_TO_PROG(ent);
+ pr_global_struct->time = sv.time;
+ PR_ExecuteProgram (touch->v->touch, "");
+
+ pr_global_struct->self = old_self;
+ pr_global_struct->other = old_other;
+ }
+ }
+ }
+}
+
+void SV_LinkEdict_AreaNode(edict_t *ent)
+{
+ areanode_t *node;
+ // find the first node that the ent's box crosses
+ node = sv_areanodes;
+ while (1)
+ {
+ if (node->axis == -1)
+ break;
+ if (ent->v->absmin[node->axis] > node->dist)
+ node = node->children[0];
+ else if (ent->v->absmax[node->axis] < node->dist)
+ node = node->children[1];
+ else
+ break; // crosses the node
+ }
+
+ // link it in
+
+ if (ent->v->solid == SOLID_TRIGGER)
+ InsertLinkBefore (&ent->area, &node->trigger_edicts, ent);
+ else
+ InsertLinkBefore (&ent->area, &node->solid_edicts, ent);
+}
+
+int SV_LinkEdict_AreaGrid(edict_t *ent)
+{
+ areagrid_t *grid;
+ int igrid[3], igridmins[3], igridmaxs[3], gridnum;
+
+ igridmins[0] = (int) ((ent->v->absmin[0] + sv_areagridbias[0]) * sv_areagridscale[0]);
+ igridmins[1] = (int) ((ent->v->absmin[1] + sv_areagridbias[1]) * sv_areagridscale[1]);
+ //igridmins[2] = (int) ((ent->v->absmin[2] + sv_areagridbias[2]) * sv_areagridscale[2]);
+ igridmaxs[0] = (int) ((ent->v->absmax[0] + sv_areagridbias[0]) * sv_areagridscale[0]) + 1;
+ igridmaxs[1] = (int) ((ent->v->absmax[1] + sv_areagridbias[1]) * sv_areagridscale[1]) + 1;
+ //igridmaxs[2] = (int) ((ent->v->absmax[2] + sv_areagridbias[2]) * sv_areagridscale[2]) + 1;
+ if (igridmins[0] < 0 || igridmaxs[0] > AREA_GRID || igridmins[1] < 0 || igridmaxs[1] > AREA_GRID || ((igridmaxs[0] - igridmins[0]) * (igridmaxs[1] - igridmins[1])) > ENTITYGRIDAREAS)
+ return false;
+
+ gridnum = 0;
+ for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
+ {
+ grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0];
+ for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++, gridnum++)
+ {
+ if (ent->v->solid == SOLID_TRIGGER)
+ InsertLinkBefore (&ent->areagrid[gridnum], &grid->trigger_edicts, ent);
+ else
+ InsertLinkBefore (&ent->areagrid[gridnum], &grid->solid_edicts, ent);
+ }
+ }
+ return true;
+}